如何使用useReducer更新对象中的数组

时间:2019-08-30 01:12:57

标签: reactjs react-hooks

我正在尝试更新状态对象。其中一项是键,其值是一个字符串数组。

我已经可以更新状态,但是它不会重新显示。

const initialState = {
  showUpload: false,
  listItems: parentDirs,
  uploadPath: [],
  fileList: null
};

const reducer = (state, action) => {
  switch (action.type) {
    case "updateListItems":
      return { ...state, listItems: action.payload };
    case "updatePath":
      return {
        ...state,
        uploadPath: [...state.uploadPath, action.payload]
      };
    default:
      return state;
  }
};

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

const pathFormat = state.uploadPath.join('/')

return (
 <p>{pathFormat}</p>
)

预期的行为是更新状态对象中的数组将触发重新渲染。

4 个答案:

答案 0 :(得分:0)

不能完全确定该数组中包含什么,但这是一个可能有用的示例。

您需要的是要定位的标识符。假设您具有以下条件:

state = {
cats: [
 {
  name: 'cat1',
  id: 1
 },
  name: 'cat2',
  id: 2
 }
],
// ... rest of state

}

要覆盖类别2,您需要执行以下操作:

//           action.type           action.payload
dispatch({ type: 'updateCats', payload: {id: 2, name: 'cat3' }})

// ... and your reducer's switch returns:
case 'updateCats':
  return {
    ...state,
    cats: [...state.cats.filter( cat => id !== payload.id), action.payload]
}

您需要通过删除旧项并再次添加来重建阵列。如何执行此操作取决于您。您可以切片和拼接,或者如果顺序不重要,则示例中使用的filter方法也可以使用。

答案 1 :(得分:0)

编辑: 我想我知道您正在尝试做的事情,并且已经更新了我的回答以反映我想我所看到的-请告诉我这是否是您正在寻找什么..

您接近!只需更改您使用dispatch的方式以及在化简器中使用action.payload上的散布运算符即可。虽然,目前尚不清楚是使用“平面”数组还是使用对象数组-我的示例使用“平面”数组展示了“简单”方式...

类似的事情应该起作用:

const initialState = {
  showUpload: false,
  listItems: "parentDirs",
  uploadPath: ["original","paths"],
  fileList: null
};

const TYPES = {
  UPDATE_LIST_ITEMS: "UPDATE_LIST_ITEMS",
  UPDATE_PATH: "UPDATE_PATH",
  JOIN_PATHS: "JOIN_PATHS"
}

const reducer = (state, action) => {
  switch (action.type) {
    case TYPES.UPDATE_LIST_ITEMS:
      return { 
        ...state, 
        listItems: action.payload 
      };
    case TYPES.UPDATE_PATH:
      return {
        ...state,
        uploadPath: [...state.uploadPath, ...action.payload]
      };
    case TYPES.JOIN_PATHS:
      return {
        ...state,
        joinedPaths: state.uploadPath.join("/")
      };
    default:
      return state;
  }
};


function Example(props) {
  const [state, dispatch] = React.useReducer(reducer, initialState);
  
  const changeUploadPath = () => {
    dispatch({type: TYPES.UPDATE_PATH, payload: ["some", "new", "paths"]})
  }
  
  const joinUploadPaths = () => {
    dispatch({type: TYPES.JOIN_PATHS});
  }
  
  return(
    <div>
      <button onClick={joinUploadPaths}>Join Upload Paths</button>
      <button onClick={changeUploadPath}>Change Upload Path</button>
      <p>{state.joinedPaths}</p>
      <br />
      <pre>{JSON.stringify(state, null, 2)}</pre>
    </div>
  );
}


ReactDOM.render(<Example />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>

答案 2 :(得分:0)

我不确定您的组件为什么不重新渲染,因为您没有显示它的工作方式。因此,我所做的并建议您进一步解决问题,是在构建一个最小的,可复制的示例来测试代码。这样,我们可以看到您如何尝试解决问题,并从上下文中看到错误。

对于React项目,我喜欢使用CodeSandboxHere is the link to my example

正如评论中的人们所提到的那样,我相信您遇到的问题与您分派操作的方式有关。在示例中,我展示了两种修改数组的方法。在第一个上,您处理组件内部的所有登录,并最终在action payload上调度完整的新数组。然后在reducer上,您必须用新的替换当前的。

在第二个示例中,我调度了一个要包含在数组中的新值。 reducer现在负责修改state

处理此逻辑的最佳位置在哪里?这取决于您要完成的工作。如果逻辑将由多个组件共享,则可以将其集中在化简器中。但是,如果不同的组件将以不同的方式处理这些数组,那么分散逻辑可能是可行的方法。

我希望这会有所帮助。

答案 3 :(得分:-1)

感谢guzmonne和其他一些人提到的每个人的帮助,这实际上是调度的实现问题。感谢您的帮助。我应该对它进行更好的调试。