【问题标题】:useReducer and state managinguseReducer 和状态管理
【发布时间】:2021-03-23 09:05:45
【问题描述】:

大家好,我正在学习 useReducer 钩子,在大多数情况下,它似乎与 redux 非常相似(减去发送到商店的操作等)

当我遇到更复杂的状态管理情况时,我似乎总是遇到问题,那就是试图以我想要的方式改变我的状态。在我的代码中,我实际上是想让用户选择一首曲目并将其添加到最喜欢的歌曲列表中。我的代码似乎正在替换状态而不是添加到它 这是我的初始状态和我的 useReducer,最后是我的 add 函数(当按下下方的按钮时,它会发送要添加到列表中的轨道

const initialState = {
  name:'',
  duration:''
};

const [favorites, dispatch]=useReducer(reducer, initialState)



const add=(song)=>{
  dispatch({type:'ADD', payload:song})
  console.log(favorites)
}

这是让我感到困惑的部分。在我的减速机里我有这个

export const reducer=(song, action)=>{
  switch(action.type){
    case 'ADD':
    return {...song, name:action.payload}
}

这实际上是在每次调用 name 时添加一个新对象:trackname 但我不想覆盖最后一项。我觉得我使用了错误的传播并且可能还返回了不正确的有效负载?

我的最终状态一直是这样的

{name: "deep end", duration: ""}
when i want it to look something like this
``
[{name: "deep end", duration: ""}
{name: "ok", duration: ""}
{name: "testtrack", duration: ""}
]`

我已经尝试将初始状态设置为这样的东西

const initialState = {
  favorites:{
[ADD TRACKS HERE]
}
};

但似乎无法正确覆盖状态,以便将其添加到数组中。它不断覆盖最后一个

【问题讨论】:

  • 查看关于不可变更新模式的指南:redux.js.org/recipes/structuring-reducers/… 您想使用 concat 或 spread 语法来更新 state 的一个属性,即数组。或者只是让数组成为整个状态!
  • 是的,这是我的问题。不变性和深拷贝。必须习惯!我最初的状态有一个对象,它本质上是一个对象数组。需要在reducer return {...song, favorites:[...song.favorites, action.payload]} 中做这样的事情,深嵌套的不可变的东西对我来说是新的,但这清楚了很多!谢谢人

标签: redux state use-reducer


【解决方案1】:

Redux 的Immutable Update Patterns 指南是一个很好的资源,介绍了如何以不改变状态的方式更新嵌套数据。

使用array 有两种主要方法可以不可变地添加元素。

  1. spread syntax:
const newArray = [...songs, newSong];
  1. 使用.concat(),它返回一个包含附加项的新数组(这与.push() 不同,它改变数组并只返回长度)。
const newArray = songs.concat(newSong);

您可以决定您想要的状态形状。将数组存储到属性 favorites 很好,但会为您的更新增加另一层复杂性。

export const reducer = (state, action) => {
  switch (action.type) {
    case "ADD":
      return { 
        ...state, 
        favorites: [...state.favorites, action.payload]
      };
    default:
      return state;
  }
};

const initialState = {
  favorites: [] // initial state has an empty array
};

const [state, dispatch] = useReducer(reducer, initialState);

// here favorites is just a property of state, not the whole state
const favorites = state.favorites;

我建议state 应该只是favorites 本身的数组。

export const reducer = (favorites, action) => {
  switch (action.type) {
    case "ADD":
      return [...favorites, action.payload]
    default:
      return favorites;
  }
};

// favorites is the whole state
// initial state is an empty array
const [favorites, dispatch] = useReducer(reducer, []);

在任何一种情况下,我们都希望 action.payload 是一个完整的歌曲对象,而不仅仅是名称。

dispatch({ type: "ADD", payload: { name: "Deep End", duration: "3:22" } });

您可以将其提取到辅助函数中。在 Redux 术语中,我们将此函数称为 Action Creator

const addFavorite = (name, duration) => ({
  type: "ADD",
  payload: { name, duration }
});

dispatch(addFavorite("Deep End", "3:22"));

【讨论】:

    猜你喜欢
    • 2020-06-12
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多