更新redux状态时如何更新本地状态(react-redux)

时间:2020-08-14 15:14:36

标签: reactjs redux react-redux react-hooks

我具有在组件内部管理的状态。 我通过将其他组件中的数据存储到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更新和添加本地状态

1 个答案:

答案 0 :(得分:0)

您发布的代码很好用,也许您可​​以提供一个示例来说明您的问题,假设您使用的是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>