【问题标题】:How to update local state when redux state is updated(react-redux)redux 状态更新时如何更新本地状态(react-redux)
【发布时间】:2020-08-14 15:14:36
【问题描述】:

我有一个在组件内部管理的状态。 我通过将其他组件的数据存储到 redux 存储中来使用它们。 但是,最后,我正在尝试收集所有数据以进行 api 调用。

const [projectData, setProjectData] = useState({})
const { userData } = useSelector((state) => state.userManage);
useEffect(() => {
    let newUsers = userData.map((x,i)=>({user_id:x.user_id, sub_user_id:x.sub_user_id}))
    setProjectState((state) =>({...state, users:newUsers}))
  }, [userData ]);


// this is handler 
const handleClick = () =>{
   dispatch(action.createProject(projectData));
}

每当我订阅的数据发生变化时,我都会尝试更新本地状态。 不知何故,它没有正确更新。当我不使用“地图”功能时,只是

setProjectState((state) =>({...state, users: userData})) <= This works. 

但它会复制 userData 中的所有内容, 所以我使用地图功能来选择特定数据,而不是所有数据。但它不起作用。

例如:

//redux store state
userData={user_id: 0, sub_id: [1,2,3], useless:"sda", useless2:"asd" }

我只想使用 user_id 和 sub_id 更新和添加本地状态

【问题讨论】:

    标签: reactjs redux react-redux react-hooks


    【解决方案1】:

    您发布的代码运行良好,也许您可​​以提供一个示例来演示您的问题,假设您的意思是 setProjectData 而不是 setProjectState:

    const { Provider, useDispatch, useSelector } = ReactRedux;
    const { createStore, applyMiddleware, compose } = Redux;
    const { useState, useEffect } = React;
    
    const initialState = {
      userData: [],
    };
    //action types
    const ADD = 'ADD';
    //action creators
    const userid = ((id) => () => id++)(1);
    const sub = ((id) => () => id++)(1);
    const add = () => ({
      type: ADD,
      payload: {
        user_id: userid(),
        sub_user_id: sub(),
        other: 'not used',
      },
    });
    const reducer = (state, { type, payload }) => {
      if (type === ADD) {
        return {
          ...state,
          userData: [payload, ...state.userData],
        };
      }
      return state;
    };
    //selectors
    const selectUserData = (state) => state.userData;
    //creating store with redux dev tools
    const composeEnhancers =
      window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    const store = createStore(
      reducer,
      initialState,
      composeEnhancers(
        applyMiddleware(() => (next) => (action) =>
          next(action)
        )
      )
    );
    
    const UserList = () => {
      const [projectData, setProjectData] = useState({});
      const userData = useSelector(selectUserData);
      useEffect(() => {
        let newUsers = userData.map((x, i) => ({
          user_id: x.user_id,
          sub_user_id: x.sub_user_id,
        }));
        setProjectData((state) => ({
          ...state,
          users: newUsers,
        }));
      }, [userData]);
      return (
        <div>
          userData:
          <pre>{JSON.stringify(userData, undefined, 2)}</pre>
          projectData:
          <pre>{JSON.stringify(projectData, undefined, 2)}</pre>
        </div>
      );
    };
    
    const App = () => {
      const dispatch = useDispatch();
      return (
        <div>
          <button onClick={() => dispatch(add())}>
            add data
          </button>
          <UserList />
        </div>
      );
    };
    
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById('root')
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
    <div id="root"></div>

    但是;而不是复制数据,最好只编写一个选择器以按照您想要的方式获取数据:

    const { Provider, useDispatch, useSelector } = ReactRedux;
    const { createStore, applyMiddleware, compose } = Redux;
    const { createSelector } = Reselect;
    
    const initialState = {
      userData: [],
    };
    //action types
    const ADD = 'ADD';
    //action creators
    const userid = ((id) => () => id++)(1);
    const sub = ((id) => () => id++)(1);
    const add = () => ({
      type: ADD,
      payload: {
        user_id: userid(),
        sub_user_id: sub(),
        other: 'not used',
      },
    });
    const reducer = (state, { type, payload }) => {
      if (type === ADD) {
        return {
          ...state,
          userData: [payload, ...state.userData],
        };
      }
      return state;
    };
    //selectors
    const selectUserData = (state) => state.userData;
    const selectProjectData = createSelector(
      [selectUserData], //re use selectUserData
      (userData) =>
        //modify user data to project data
        userData.map((x, i) => ({
          user_id: x.user_id,
          sub_user_id: x.sub_user_id,
        }))
    );
    //creating store with redux dev tools
    const composeEnhancers =
      window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    const store = createStore(
      reducer,
      initialState,
      composeEnhancers(
        applyMiddleware(() => (next) => (action) =>
          next(action)
        )
      )
    );
    
    const UserList = () => {
      //no state, no effect, just select the way you want it
      const projectData = useSelector(selectProjectData);
      //if you want userData as well you can select that too
      // const userData = useSelector(selectUserData)
      return (
        <div>
          <pre>{JSON.stringify(projectData, undefined, 2)}</pre>
        </div>
      );
    };
    
    const App = () => {
      const dispatch = useDispatch();
      return (
        <div>
          <button onClick={() => dispatch(add())}>
            add data
          </button>
          <UserList />
        </div>
      );
    };
    
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById('root')
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
    <div id="root"></div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-07
      • 2019-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-08
      • 2021-10-29
      相关资源
      最近更新 更多