如何使用useState仅更新对象数组中的特定对象?

时间:2020-03-31 06:51:32

标签: reactjs react-redux

我刚刚在我的React应用程序中实现了类似系统的功能,但是现在我一直在努力更改特定对象的状态,而不是更改整个对象数组的状态。.

{post.likes.some(u => u.user == _id) ? (
  <Button
    variant="link"
    size={`sm`}
    className={`mr-1`}
    onClick={() => {removeLike(post._id) ; setIconColor('success') ; setLikes(post.likes.length) }}
  >
    <i className={`fa fa-heart text-${iconColor} like mr-1`}></i>{likes}
  </Button>
) : (
  <Button
    variant="link"
    size={`sm`}
    className={`mr-1`}
    onClick={() => {addLike(post._id) ; setIconColor('danger') ; setLikes(post.likes.length) }}
  >
    <i className={`fa fa-heart text-${iconColor} like mr-1`}></i>{likes}
  </Button>
)}

如前所述,它位于通过对象数组运行的组件内部。

现在,这就是我在return语句之前的组件中的内容:

const [iconColor, setIconColor] = useState('');
const [likes, setLikes] = useState(0);

如果我按原样运行它,它将更新每个单个对象的状态,而不是我单击的对象的状态。这是我的实际问题: useState() updating muliple objects

更新:我也在使用redux-thunk:

// @desc     Like a post
// @route    PUT /api/v1/posts/:id/like
// @access   Private
// @status   DONE
export const addLike = id => async dispatch => {
  try {
    const res = await axios.put(`/api/v1/posts/${id}/like`);

    return dispatch({
      type: UPDATE_LIKES,
      payload: {
        id,
        likes: res.data
      }
    });
  } catch (err) {
    return dispatch({
      type: POST_ERROR,
      payload: { msg: err.response && err.response.statusText, status: err.response && err.response.status }
    });
  }
};

// @desc     Dislike a post
// @route    PUT /api/v1/posts/:id/dislike
// @access   Private
// @status   DONE
export const removeLike = id => async dispatch => {
  try {
    const res = await axios.put(`/api/v1/posts/${id}/dislike`);

    return dispatch({
      type: UPDATE_LIKES,
      payload: {
        id,
        likes: res.data
      }
    });
  } catch (err) {
    return dispatch({
      type: POST_ERROR,
      payload: { msg: err.response && err.response.statusText, status: err.response && err.response.status }
    });
  }
};

然后这些函数返回一个连接到我的reducer的调度程序:

case UPDATE_LIKES:
  return {
      ...state,
      likes: state.timeline.map((post) =>
        post._id === payload.id && { [post._id]: payload.likes.length }
      ),
      // like: !state.like,
      // likes: console.log(
      //   state.timeline.map(post =>
      //     post._id === payload.id ? { ...post, likes: payload.likes } : post
      //   )
      // ),
      loading: false
  };

4 个答案:

答案 0 :(得分:0)

您需要具有一个变量likes的数组。目前,您只是多次更改同一变量的值。只需将like数组的索引与父数组的索引相同即可。甚至更好:将赞数存储在帖子/卡片的对象中。

答案 1 :(得分:0)

要仅更新对象数组中的特定对象,可以尝试以下操作:

let stateObj = {
    one: [],
    two: [],
    three: [],
    // and so on
}

因此您可以从这种大状态获取特定的对象或数组,例如:

stateObj.one

现在您可以执行此操作,一旦其值更新,只需将其替换为原来的。

答案 2 :(得分:0)

您需要为每个帖子跟踪likes。为此,您可以使用诸如{ post_id: like_count}

之类的映射

因此您的状态将变为:

const [likes, setLikes] = useState({});

点击监听器将是:

onClick={() => {addLike(post._id) ; setIconColor('danger') ; setLikes({...likes, [post._id]: post.likes.length}) }}

显示类似计数将是:

<i className={`fa fa-heart text-${iconColor} like mr-1`}></i>{likes[post._id] || 0}

答案 3 :(得分:0)

我不认为,您需要为此提供状态。据我从您的代码中了解,您可以实现以下目标。

{post.likes.some(u => u.user == _id) ? (
  <Button
    variant="link"
    size={`sm`}
    className={`mr-1`}
    onClick={() => {removeLike(post._id)}}
  >
    <i className={`fa fa-heart text-danger like mr-1`}></i>{post.likes.length}
  </Button>
) : (
  <Button
    variant="link"
    size={`sm`}
    className={`mr-1`}
    onClick={() => {addLike(post._id)}}
  >
    <i className={`fa fa-heart text-success like mr-1`}></i>{post.likes.length}
  </Button>
)}

,并且您的addLikeremoveLike函数应更新post,这将强制重新渲染组件。因此,它应该可以按预期工作。