useReducer 和状态管理

时间:2021-03-23 09:05:45

标签: redux state use-reducer

嘿伙计们,我正在学习 useReducer 钩子,并且在大多数情况下它似乎与 redux 非常相似(减去发送到商店等的动作)

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

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]
}
};

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

1 个答案:

答案 0 :(得分: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"));