在函数组件中从 Redux Store 接收新值时 useState 不起作用

useState not working when receiving new values from Redux Store in Function Component

关于这个 StackBlitz (you can play with) 我有以下代码:

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;

预期功能

  1. “绿色”select默认设置
  2. 你select“黄色”,下面出现一条建议(你在控制台上得到:“黄色”)
  3. 您 select“绿色”并且建议消失(您在控制台上得到:“绿色”)
  4. 执行上面的第 2 步
  5. 您点击link:“立即更改!”
  6. 选项“绿色”得到 select 编辑并且建议消失(您在控制台上得到:“绿色”)

我的问题是:

第 6 步并不完全有效,因为即使建议消失了,这很好,选项:“绿色”没有得到 selected 并且在控制台上我仍然得到:“黄色”。

由于某种原因,该行...

const [ formValues, setFormValues ] = useState(...);

... 未保存变量存储中的值:formValues 因为 userData 具有预期值,如下图所示...

知道如何进行这项工作吗?

谢谢!

我不知道获取新储值的正确方法是什么。但我可以建议的是创建一个 useEffect 挂钩来设置每次 userData 更改时运行的新表单值。

useEffect(() => {
    setFormValues(userData)
  }, [userData])

不,那是错误的React.useState(defaultValue)它只是用于组件渲染的 React.useState 的默认值,它不会监听新的变化。

你需要使用 React.useEffect() 钩子,如果你将依赖项数组留空,那么 useEffect 将只在组件渲染时调用一次,但如果你将依赖项作为你的 redux 数据传递然后每次你的依赖数据改变时 useEffect 将被调用。

最后你的代码会像这样

const dispatch = useDispatch();
  const userData = useSelector(state => state.user);

  const initialValues = {
    color: 'Green',
  };

  const [ formValues, setFormValues ] = useState(initialValues);
  
  React.useEffect(()=>{
    setFormValues((userData.length > 0) ? userData : initialValues);
    // cleanup function which will be invoked on component unmount
    return ()=> {
      setFormValues(userData)
    }
  },[useData]);

  console.log(JSON.stringify({ userData, formValues }));

  const onSubmit = (values) => {
    dispatch(userActions.save(values));
  };