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