Как использовать useState только для обновления указанного c объекта из массива объектов? - PullRequest
0 голосов
/ 31 марта 2020

Я только что реализовал функциональность подобной системы в своем приложении React, но теперь я изо всех сил пытался изменить состояние указанного объекта c вместо всего массива объектов, который является текущим поведением.

{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 () обновляет несколько объектов

ОБНОВЛЕНИЕ: Я также использую 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 }
    });
  }
};

Эти функции затем возвращают диспетчеризацию который подключается к моему редуктору:

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 голосов
/ 31 марта 2020

Не думаю, что для этого нужны штаты. Насколько я понимаю из вашего кода, вы можете добиться того же, что и ниже.

{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>
)}

и ваши addLike и removeLike функции должны обновить post, что приведет к повторной визуализации вашего компонента. И, следовательно, он должен работать как ожидалось.

0 голосов
/ 31 марта 2020

Чтобы обновить только конкретный c объект из массива объектов, вы можете попробовать что-то вроде:

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

Таким образом, вы можете получить конкретный c объект или массив из этого большого состояния, например:

stateObj.one

и теперь вы можете делать с ним все, что захотите, и после обновления его значений просто замените его на исходное.

0 голосов
/ 31 марта 2020

Вам нужно отслеживать 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}
0 голосов
/ 31 марта 2020

Вам потребуется массив переменных likes. В настоящее время вы просто меняете значение одной и той же переменной много раз. Просто имейте индекс подобного массива такой же, как индекс вашего родительского массива. Или, что еще лучше: сохраните счетчик объектов внутри объекта почтовой открытки / открытки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...