反应 useContext 丢失状态

React useContext losing state

过去几天我一直在努力解决一个问题:

我正在为表单字段使用上下文提供程序,但无论出于何种原因,当我使用备忘录时,字段总是相互覆盖。

提供商:

export const Context = React.createContext();

function Form_Provider({ values, onChange, children }) {
  return (
    <Context.Provider value={{ values, onChange }}>
      {children}
    </Context.Provider>
  )
});
export default Form_Provider

字段:

function Field({ label, name }) {
  const { values, onChange } = useContext(Context);
  return (
      <Memorable
        label={label}
        onChange={({ target: t }) => onChange({ name, value: t.value })}
        value={values[name]}
      />
  );


}

const Memorable = React.memo(props => {
  return (
      <Form.Item label={props.label}>
        <Input
          value={props.value}
          onChange={props.onChange}
        />
      </Form.Item>
    </>
  )
}, ({ value: newValue}, { value: oldValue }) => newValue == oldValue)

表格

const [formValues, setFormValues] = useState({ field1: 'Foo', field2: 'Bar' });

<Form.Provider
  values={formValues}
  onChange={({ name, value }) => setFormValues({...formValues, [name]: value }))
>
  <Form.Field name='field1' label="Field 1" />
  <Form.Field name='field2' label="Field 2" />
</Form.Provider>

(尽量简化)

在我的实际代码中,我添加了一个 json 打印美化器来跟踪每个字段的状态,当我只编辑一个字段时,它会一直运行到每个字段。但是,一旦我开始编辑另一个字段,我编辑的第一个字段就会恢复到其原始状态 and/or 过去状态之间的其他一些奇怪的状态。

如果我不使用备忘录,它可以工作,但这不是解决方案,因为我将处理很多字段,这会导致大量重新渲染。

有人知道这里发生了什么吗?

加法:

我已经尝试为此使用一个内部减速器并传递一个调度函数。只要我不尝试在提供者之外管理状态,一切正常。

我很确定问题是您正在从这里记住 formValues 的原始值:

onChange={({ name, value }) => setFormValues({...formValues, [name]: value }))

假设 field1 的值发生了变化。它调用 onChange 处理程序,它将 ...formValues - 组件安装时存在的值 - 与 field1.

的新值合并

现在 React.memo 中的相等函数为 field1 returns false,因为值不同。该特定字段重新呈现以接收其新值,以及 ...formValues 的新值。然而,其他字段 not 重新呈现。对于他们来说,...formValues 仍然意味着状态的值,因为它存在于他们最后一次重新渲染时,也就是组件安装时。

如果您现在更改 field2 的值,它会将状态设置为将原始状态与 field2 的新值合并的结果。因此 field1 被重置,因为它的值现在又变回原来的值。

一个简单的解决方案是使用 setState 的回调版本,它始终使用状态的当前值:

onChange={({ name, value }) => setFormValues(fv => {...fv, [name]: value }))

但是,我很想不这样做,而是完全摆脱记忆。这是因为您的相等函数实际上并没有准确反映提供给组件的 props 变化的方式。我相信这里的性能提升也可以忽略不计,因为组件很小并且本身不会渲染任何其他组件。

假设没有与值变化相关的动画,它的执行成本非常低,并且不适合记忆,这也逃脱了内置的 React 优化。在实施之前,您应该仔细考虑决定您是否真的需要它。