簡體   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