繁体   English   中英

使用 state 和 onChange 反应 useMemo 依赖循环

[英]React useMemo dependency loop with state and onChange

在下面的代码中FormExample正在呈现。 Form is a 是SampleTextField的包装器,用于处理所有子字段的更改和 state。 我正在尝试使用useMemo以便一个字段的更改不会重新呈现另一个字段。

The problem is that the handleChange function is cached with its state scope so if I change the first field, and then edit the second the state is overwritten with the old value of the first field.

我可以在useCallback中添加 wrap handleChange ,但它只会与它引用的 onChange 产生相同的问题。

我也尝试将handleChange 添加到useMemo 的依赖数组中,但是因为在每个state 更改(因为重新渲染)上都会创建一个新的handleChange 实例(因为重新渲染),所以它与没有useMemo 相同。

有没有我可以用来解决这个问题的模式?

import {TextField} from '@material-ui/core';
import * as React from 'react';
import {useContext, useState} from 'react';

const FormContext = React.createContext<any>({});
const Form = ({state, onChange, children}: any) => {

  const handleChange = (name: any, val: any) => {
    onChange({...state, [name]: val});
  }

  return (
    <FormContext.Provider value={{state, handleChange}}>
      {children}
    </FormContext.Provider>
  );
}

const SampleTextField = ({name}: any) => {
  const {state, handleChange} = useContext(FormContext);
  const value = state[name]

  return React.useMemo(() => {
    return (
      <TextField name={name} value={value} onChange={(e: any) => handleChange(e.target.name, e.target.value)}/>
    );
  }, [value]);
}

const FormExample = () => {
  const [state, setState] = useState({text1: "", text2: ""});

  return (
    <Form state={state} onChange={setState}>
      <SampleTextField name="text1"/>
      <br/><br/>
      <SampleTextField name="text2"/>
    </Form>
  )
}

export default FormExample;

您可以使用useCallback使您的handleChange参考稳定。 请注意我如何使用setState的 function 形式,它接受当前 state 作为第一个参数

import { TextField } from "@material-ui/core";
import * as React from "react";
import { useContext, useState, useMemo, useCallback, createContext } from "react";

const FormContext = createContext<any>({});
const Form = ({ state, onChange, children }: any) => {
  const handleChange = useCallback(
    (name: any, val: any) => {
      onChange((state) => ({ ...state, [name]: val }));
    },
    [onChange]
  );

  const context = useMemo(
    () => ({
      state,
      handleChange,
    }),
    [state, handleChange]
  );

  return (
    <FormContext.Provider value={context}>{children}</FormContext.Provider>
  );
};

const SampleTextField = ({ name }: any) => {
  const { state, handleChange } = useContext(FormContext);
  const value = state[name];

  return useMemo(
    () => (
      <TextField
        name={name}
        value={value}
        onChange={(e: any) => handleChange(e.target.name, e.target.value)}
      />
    ),
    [value, handleChange]
  );
};

const FormExample = () => {
  const [state, setState] = useState({ text1: "", text2: "" });

  return (
    <Form state={state} onChange={setState}>
      <SampleTextField name="text1" />
      <br />
      <br />
      <SampleTextField name="text2" />
    </Form>
  );
};

export default FormExample;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM