从函数组件中的 Redux Store 接收新值时,useState 不起作用
在此 StackBlitz (你可以玩) 我有以下代码:
App.js
import { Field, Form, Formik } from 'formik';
import React, { useState } from 'react';
import { Provider, useDispatch, useSelector } from 'react-redux';
import store, { userActions } from './store';
const Suggestion = () => {
const dispatch = useDispatch();
const { color } = useSelector(state => state.user);
return (color === 'Yellow') ? (
<div>
We recommend you to change to Green.<br />
<a href="#" onClick={() => { dispatch(userActions.save({ color: 'Green' })); }}>Change Now!</a>
</div>
) : null;
};
const MyComp = () => {
const dispatch = useDispatch();
const userData = useSelector(state => state.user);
const initialValues = {
color: 'Green',
};
const [ formValues, setFormValues ] = useState((userData.length > 0) ? userData : initialValues);
console.log(JSON.stringify({ userData, formValues }));
const onSubmit = (values) => {
dispatch(userActions.save(values));
};
return (
<Formik
initialValues={formValues}
onSubmit={onSubmit}
enableReinitialize
>
{formik => {
const handleChange = (partialUserData) => {
setFormValues({
...formValues,
...partialUserData
});
formik.submitForm();
};
return (
<Form>
<h2>What Color do you use?</h2>
<Field id="color" as="select" value={formValues.color} onChange={(e) => { handleChange({ color: e.target.value }); }}>
<option value=''>Select...</option>
<option value='Green'>Green</option>
<option value='Yellow'>Yellow</option>
</Field>
<Suggestion />
</Form>
);
}}
</Formik>
);
};
export default () => {
return (
<Provider store={store}>
<MyComp />
</Provider>
);
};
store.js
import { configureStore, createSlice } from '@reduxjs/toolkit';
const userSlice = createSlice({
name: 'user',
initialState: {},
reducers: {
save(state, action) {
for (const key in action.payload) {
state[key] = action.payload[key];
}
},
},
});
const store = configureStore({
reducer: {
user: userSlice.reducer,
},
devTools: true,
});
export const userActions = userSlice.actions;
export default store;
预期功能
- 默认选择“绿色”
- 您选择“黄色”,下面会出现一条建议 (你得到:控制台上的“黄色”)
- 您选择“绿色”,建议消失(您在控制台上看到:“绿色”)
- 执行上面的步骤 2
- 您单击链接:“立即更改!”
- 选项“绿色”被选中并且建议消失(您在控制台上看到:“绿色”)
我的问题是:
第 6 步没有完全起作用,因为即使建议消失(这很好),该选项:“绿色”没有被选择,在控制台上我仍然得到:“黄色”。
由于某种原因,该行...
const [ formValues, setFormValues ] = useState(...);
...没有保存变量中存储的值:formValues
,因为userData
具有预期值,如您在下面的图片...
任意关于如何使这项工作有效的想法?
谢谢!
On this StackBlitz (you can play with) I have the following code:
App.js
import { Field, Form, Formik } from 'formik';
import React, { useState } from 'react';
import { Provider, useDispatch, useSelector } from 'react-redux';
import store, { userActions } from './store';
const Suggestion = () => {
const dispatch = useDispatch();
const { color } = useSelector(state => state.user);
return (color === 'Yellow') ? (
<div>
We recommend you to change to Green.<br />
<a href="#" onClick={() => { dispatch(userActions.save({ color: 'Green' })); }}>Change Now!</a>
</div>
) : null;
};
const MyComp = () => {
const dispatch = useDispatch();
const userData = useSelector(state => state.user);
const initialValues = {
color: 'Green',
};
const [ formValues, setFormValues ] = useState((userData.length > 0) ? userData : initialValues);
console.log(JSON.stringify({ userData, formValues }));
const onSubmit = (values) => {
dispatch(userActions.save(values));
};
return (
<Formik
initialValues={formValues}
onSubmit={onSubmit}
enableReinitialize
>
{formik => {
const handleChange = (partialUserData) => {
setFormValues({
...formValues,
...partialUserData
});
formik.submitForm();
};
return (
<Form>
<h2>What Color do you use?</h2>
<Field id="color" as="select" value={formValues.color} onChange={(e) => { handleChange({ color: e.target.value }); }}>
<option value=''>Select...</option>
<option value='Green'>Green</option>
<option value='Yellow'>Yellow</option>
</Field>
<Suggestion />
</Form>
);
}}
</Formik>
);
};
export default () => {
return (
<Provider store={store}>
<MyComp />
</Provider>
);
};
store.js
import { configureStore, createSlice } from '@reduxjs/toolkit';
const userSlice = createSlice({
name: 'user',
initialState: {},
reducers: {
save(state, action) {
for (const key in action.payload) {
state[key] = action.payload[key];
}
},
},
});
const store = configureStore({
reducer: {
user: userSlice.reducer,
},
devTools: true,
});
export const userActions = userSlice.actions;
export default store;
Expected functionality
- "Green" is selected by default
- You select "Yellow" and a suggestion appears underneath (you get: "Yellow" on the console)
- You select "Green" and the suggestion disappears (you get: "Green" on the console)
- Do Step 2 above
- You click the link: "Change Now!"
- Option "Green" gets selected and the suggestion disappears (you get: "Green" on the console)
My Problem is:
Step 6 is not totally working because even though the suggestion disappears which is fine, the option: "Green" doesn't get selected and on the console I still get: "Yellow".
For some reason, the line...
const [ formValues, setFormValues ] = useState(...);
... is not saving values from the Store on variable: formValues
since the userData
has the expected values as you can see on the image below...
Any idea on how to make this work?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,这是错误的
React.useState(defaultValue)
它只是用于组件渲染的React.useState
的默认值,它不会监听新的更改。您需要使用
React.useEffect()
钩子,如果您将依赖项数组留空,则它会获取依赖项数组,然后useEffect
将仅在组件渲染时调用一次,但如果您通过依赖作为您的 redux 数据,然后每次您的依赖数据发生更改时,都会调用useEffect
。所以最后你的代码将是这样的
no that is wrong
React.useState(defaultValue)
it's just the default value for theReact.useState
which is used on component render and it does not listen for new changes.You need to use
React.useEffect()
hook which takes the dependencies array if you leave the dependencies array empty thenuseEffect
will only be invoked once on component render but if you pass dependency as your redux data then every time your dependency data is changeduseEffect
will be invoked.So finally you code will be like this
我不知道捕获新存储值的正确方法是什么。但我可以建议的是创建一个 useEffect 挂钩来设置每次
userData
更改时运行的新表单值。I don't know what is the correct way to capture the new stored value. But what i can suggest is to create a useEffect hooks to set new form values that runs every time
userData
changes.