反应-将用户添加到收藏夹列表

时间:2019-09-13 10:55:00

标签: javascript reactjs

我有一个简单的用户列表,其中包含来自以下api的一些详细信息:https://gorest.co.in/public-api/users,我想在其中将所选用户添加到收藏夹列表中。我正在使用react-router在页面之间导航。 React可以做到吗?还是我还需要Redux?

我在这里有完整的LIVE EXAMPLE,其中包含用户页面和收藏夹。

以下是用户列表的代码:

import React from "react";
import axios from "axios";

import NavLinks from "./components/navLink";

export default class UserList extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      list: [],
      addToFav: false
    };
    this.list = [];
  }

  componentDidMount() {
    this.getList();
  }

  /* get users list */
  getList = async () => {
    const api =
      "https://gorest.co.in/public-api/users?_format=json&access-token=3qIi1MDfD-GXqOSwEHHLH73Y3UitdaFKyVm_";

    await axios
      .get(api)
      .then(response => {
        this.list = response.data.result;
        this.setState({
          list: this.list
        });
      })
      .catch(err => {
        console.log(err);
      });
  };

  addToFav = () => {
    this.setState(
      {
        addToFav: !this.state.addToFav
      },
      () => console.log(this.state.addToFav)
    );
  };

  render() {
    let style = {
      display: "grid",
      gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))",
      padding: "1rem",
      gridGap: "1rem 1rem"
    };

    return (
      <div>
        <NavLinks />
        <ul style={style}>
          {this.state.list.map(user => {
            return (
              <li key={user.id}>
                <div>
                  <img className="thumb" alt="" src={user._links.avatar.href} />
                </div>

                <div className="userInfo">
                  <p>
                    {user.first_name} {user.last_name}
                  </p>
                </div>
                <button onClick={this.addToFav}>Add to Favorites</button>
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
}

谢谢!

7 个答案:

答案 0 :(得分:1)

我对您的文件做了一些更改-https://github.com/navabi/JustifiedTextView

答案 1 :(得分:1)

这是一个有效的代码框:https://codesandbox.io/s/brave-fire-4kd4p

这种思路几乎遵循@Chris G所提到的。具有保存用户列表和收藏夹列表的顶级状态。然后将它们作为道具传递给各个组件。

App.js

在此处而不是在UserList组件中放置您的API,以防止不必要的重新渲染。

import React, { Component } from "react";
import UserList from "./userList";
import FavoriteList from "./favoriteList";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import axios from "axios";

export default class App extends Component {
  state = {
    list: [],
    favorites: []
  };

  addFavorite = favorite => {
    const { favorites } = this.state;

    if (!favorites.some(alreadyFavorite => alreadyFavorite.id == favorite.id)) {
      this.setState({
        favorites: [...this.state.favorites, favorite]
      });
    }
  };

  getList = async () => {
    const api =
      "https://gorest.co.in/public-api/users?_format=json&access-token=3qIi1MDfD-GXqOSwEHHLH73Y3UitdaFKyVm_";

    await axios
      .get(api)
      .then(response => {
        this.setState({
          list: response.data.result
        });
      })
      .catch(err => {
        console.log(err);
      });
  };

  componentDidMount() {
    this.getList();
  }

  render() {
    return (
      <Router>
        <Switch>
      <Route
        path="/"
        exact
        render={() => (
          <UserList list={this.state.list} addFavorite={this.addFavorite} />
        )}
      />
      <Route
        path="/favorites"
        render={() => <FavoriteList favorites={this.state.favorites} />}
      />
    </Switch>
  </Router>
);

} }

UserList.js

在单击按钮时调用addFavorite事件处理程序,以将该项目传递回父状态。

import React from "react";

import NavLinks from "./components/navLink";

export default class UserList extends React.Component {
  render() {
    let style = {
      display: "grid",
      gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))",
      padding: "1rem",
      gridGap: "1rem 1rem"
    };

    return (
      <div>
        <NavLinks />
        <ul style={style}>
          {this.props.list.map(user => {
            return (
              <li key={user.id}>
                <div>
                  <img className="thumb" alt="" src={user._links.avatar.href} />
                </div>

                <div className="userInfo">
                  <p>
                    {user.first_name} {user.last_name}
                  </p>
                </div>
                <button onClick={() => this.props.addFavorite(user)}>
                  Add to Favorites
                </button>
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
}

Favorite.js

使用作为道具传入的favorites数组并对其进行迭代。

import React from "react";

import NavLinks from "./components/navLink";

export default class FavoriteList extends React.Component {
  constructor(props) {
    super(props);

    this.state = {};
  }

  render() {
    const { favorites } = this.props;
    return (
      <div>
        <NavLinks />
        <ul>
          {favorites.map(user => {
            return (
              <li key={user.id}>
                <div>
                  <img className="thumb" alt="" src={user._links.avatar.href} />
                </div>

                <div className="userInfo">
                  <p>
                    {user.first_name} {user.last_name}
                  </p>
                </div>
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
}

答案 2 :(得分:0)

  

React可以实现吗?还是我还需要Redux?

如果没有redux,仅使用组件状态就可以解决大多数(如果不是全部)问题。将状态传递给需要它的组件变得越来越困难,您拥有的状态越全局,并且需要更多不同深度的组件来访问和更新它。

在您的情况下,将收藏夹存储在树上方的组件状态中,然后将其传递给使用它的组件可能就足够了。您可以将其直接传递给组件,也可以使用react context使树中深层的组件可以访问它。

一个简单的示例:

const FavoritesContext = React.createContext({favorites: []});

const FavoritesProvider = ({children}) => {
    const [favorites, setFavorites] = useState([]);

    const add = useCallback(favorite => setFavorites(current => [...current, favorite]), [setFavorites]);

    return (
        <FavoritesContext.Provider value={{favorites, add}}>
            {children}
        </FavoritesContext.Provider>
};

您可以这样使用它:

<FavoritesProvider>
    <MyApp />
</FavoritesProvider>

然后在应用程序组件中的任意位置:

const MyComponent = () => {
    const {favorites, add} = useContext(FavoritesContext);

    const [draft, setDraft] = useState('');

    const handleChange = event => setDraft(event.target.value);
    const handleAdd = () => {
        add(draft);
        setDraft('');
    };

    return (
      <div>
          <ul>
              {favorites.map(favorite => <li>{favorite}</li>)}
          </ul>
          <input value={draft} type="text" onChange={handleChange} />
          <button onClick={handleAdd}>Add</button>
      </div>
    );
}

在这个简单的示例中,收藏夹只是文本,但也可以是对象。它还演示了如何提供用于添加收藏夹的处理程序。您可以实现例如以相同的方式删除收藏夹的处理程序。

保留您的收藏夹是您可能需要处理的另一个主题。您可以使用例如为此,您可以使用localStorage,也可以将其存储在服务器上的数据库中,并在应用首次安装时获取。

答案 3 :(得分:0)

一种方法是使用浏览器的本地存储。

但是这种方式有点昂贵且同步。

只要通过以下方式更改收藏夹项目的状态,就更新列表

localStorage.setItem('users',JSON.stringify(users));

然后通过

查找喜欢的物品
localStorage.getItem('users');//You need to parse this by JSON.parse()

在对象列表中维护一个isFavorite变量。

let users=[{name:"Mr.A",isFavorite:false},{name:"Mr.B",isFavorite:true},...];

在点击收藏按钮this.addToFav时,进行如下更改

addToFav=user=>{
  const {users}=this.state;
  this.setState({
    users:users.map(userObject=>userObject.id===user.id? 
  {...userObject,isFavorite:!userObject.isFavorite}:user)
    },()=>{saveToLocal(this.state.users)});
}

现在,即使重新加载页面并一直停留到清除存储空间,您也可以访问收藏夹项目。为此,请使用此localStorage.clear()

答案 4 :(得分:0)

我做了相应的更改,请尝试

https://codesandbox.io/s/youthful-poincare-7oeh0

关键是您可以按如下所示使用推送状态链接

<Link to={{ pathname: "/favorites", state: { favList: this.props.favList }}} onClick={() => this.forceUpdate()}>

随后在您的收藏夹页面调用下检索状态

this.props.location.state.favList

答案 5 :(得分:0)

我通过使用react上下文对代码进行了一些更改。 我不会为此使用redux,因为我认为这会太过分了。 无论如何,这里是更新的沙箱...

Link for sandbox

答案 6 :(得分:-1)

首先,我将您的onClick更改为此:

<button onClick={() => this.addToFav(user.id)}>Add to Favorites</button>

这将允许您将ID传递给addToFave函数。 然后,我将添加一个名为faves(数组)的新状态,每当有人单击添加按钮时,我都会将其ID添加到此数组中。当您要显示收藏夹时,这将允许您过滤原始列表。

  this.state = {
      list: [],
      faves: [],
    };
  }

  addToFav = (id) => {
    this.setState(prevState => ({
        faves: [...prevState.faves, id],
    }));
  };

当我想使用收藏夹列表而不是普通列表时,我会这样做:

const favesList = [];
this.state.list.map(listItem => 
    this.state.faves.find(
        faveId => listItem.id === faveId
    ) && favesList.push(item);

然后我将其传递给faves组件