web-dev-qa-db-fra.com

Bonne façon de mettre à jour l'état dans les réducteurs redux

Je suis un novice en syntaxe redux et es6. Je crée mon application avec le tutoriel officiel Redux et avec ce exemple

Il y a un extrait JS ci-dessous. Mon point - pour définir les cas REQUEST_POST_BODY et RECEIVE_POST_BODY dans posts réducteur Principal difficile - trouver et mettre à jour le bon objet en magasin.

J'essaie d'utiliser le code de l'exemple:

  return Object.assign({}, state, {
    [action.subreddit]: posts(state[action.subreddit], action)
  })

Mais il utilisait un simple tableau de messages. Il n'est pas nécessaire de trouver le bon post par id.

Voici mon code:

  const initialState = {
    items: [{id:3, title: '1984', isFetching:false}, {id:6, title: 'Mouse', isFetching:false}]
  }

  // Reducer for posts store
  export default function posts(state = initialState, action) {
    switch (action.type) {
    case REQUEST_POST_BODY:
      // here I need to set post.isFetching => true
    case RECEIVE_POST_BODY:
      // here I need to set post.isFetching => false and post.body => action.body
    default:
      return state;
    }
  }

  function requestPostBody(id) {
    return {
      type: REQUEST_POST_BODY,
      id
    };
  }

  function receivePostBody(id, body_from_server) {
    return {
      type: RECEIVE_POST_BODY,
      id,
      body: body_from_server
    };
  }

  dispatch(requestPostBody(3));
  dispatch(receivePostBody(3, {id:3, body: 'blablabla'}));
14
Max Vorozhcov

Avec des tableaux

Si vous préférez vous en tenir à des tableaux, vous pouvez écrire un réducteur qui s’attaque uniquement à des objets post simples.

export default function reducePost(post, action) {
  if(post.id !== action.id) return post;

  switch(action.type) {
  case REQUEST_POST_BODY:
    return Object.assign({}, post, { isFetching: true });
  case RECEIVE_POST_BODY:
    return Object.assign({}, post, { isFetching: false, body: action.body });
  default:
    return post;
}

Votre réducteur de racine deviendrait:

export default function posts(state = initialState, action) {
  return state.map(post => reducePost(post, action);
}

Nous venons d'exécuter notre nouveau réducteur sur chaque message de la liste, pour renvoyer un tableau mis à jour de messages. Dans ce cas, l'identifiant unique garantira qu'un seul élément sera modifié.

Avec des objets

Si chaque élément a un identifiant de chaîne/numéro unique, vous pouvez alors retourner votre tableau et utiliser à la place une object.

const initialState = {
  items: {
    3: {id:3, title: '1984', isFetching:false},
    6: {id:6, title: 'Mouse', isFetching:false}
  };
}

Ensuite, vous pouvez simplifier votre réducteur.

switch (action.type) {
case REQUEST_POST_BODY:
  let id = action.id;
  return Object.assign({}, state, {
    [id]: Object.assign({}, state[id], { isFetching: true })
  });
case RECEIVE_POST_BODY:
  let id = action.id;
  return Object.assign({}, state, {
    [id]: Object.assign({}, state[id], {
      isFetching: false,
      body: action.body
    })
  });
default:
  return state;
}

Si vous souhaitez également essayer une syntaxe ES7, vous pouvez activer l'opérateur de propagation d'objet avec Babel et réécrire les appels vers Object.assign.

switch (action.type) {
case REQUEST_POST_BODY:
  let id = action.id;
  return {
    ...state,
    [id]: {...state[id], isFetching: true }
  };
case RECEIVE_POST_BODY:
  let id = action.id;
  return {
    ...state,
    [id]: {
      ...state[id],
      isFetching: false,
      body: action.body
    }
  };
default:
  return state;
}

Si vous ne souhaitez pas utiliser la syntaxe spread, il est toujours possible de rendre Object.assign un peu plus acceptable.

function $set(...objects) {
  return Object.assign({}, ...objects); 
}
case RECEIVE_POST_BODY:
  let id = action.id;
  return $set(state, {
    [id]: $set(state[id], {
      isFetching: false,
      body: action.body
    })
  });
24
Dan Prince

Si je comprends bien, vous avez du mal à trouver le message spécifique que vous souhaitez.

Tout d’abord, le fait de mettre à jour le tableau et l’objet qu’il contient rend la lecture et la maintenance difficiles. Je vous suggère de regarder cette courte vidéo expliquant la composition des réducteurs à l'aide de tableaux . Vous pouvez simplifier votre code en utilisant la technique décrite ici.

Dans votre cas, vous auriez un réducteur posts et un réducteur post, tandis que le réducteur posts appelle le réducteur post.

Pour ce qui est de trouver le bon objet sur lequel travailler, la suggestion de Dan Prince facilite la tâche… .. Avoir une carte d'objet au lieu d'un tableau vous faciliterait la tâche. Extrait de code pertinent de la réponse de Dan:

const initialState = {
  items: {
    3: {id:3, title: '1984', isFetching:false},
    6: {id:6, title: 'Mouse', isFetching:false}
  ];
}
1
Moti Azu