React Context перерисовка всех дочерних элементов

Реализован компонент формы

Подключение:

import React from 'react';

import { Form, Input, Button } from './../Design/Components';

interface PropsTypes {
    ...
}

const AddGroupModal = (props: PropsTypes): JSX.Element => {

    const formSubmit = () => {
        
    }

    return (
        <Form
            initialValues={{
                title: '',
                name: ''
            }}
            onSubmit={formSubmit}
        >
            <Form.Field
                name="title"
            >
                <Input placeholder="Наименование" />
            </Form.Field>
            <Form.Field
                name="name"
            >
                <Input placeholder="Еще поле" />
            </Form.Field>
            <Button>Сохранить</Button>
        </Form>
    )
}

export default AddGroupModal;

Компонент Form

import React, { useState } from 'react';

import { FormField } from './FormField';

import { FormProps, FormContextT } from './../../../types/form';

import './style.scss';

export const FormContext = React.createContext<FormContextT>({
    formData: {},
    handleFieldChange: () => {}
});

export const Form = (props: FormProps): JSX.Element => {

    const { children, initialValues, className, onSubmit } = props;

    const [ formData, setFormData] = useState(initialValues);

    const handlerSubmit = (e: React.SyntheticEvent): void => {
        e.preventDefault();
        
        onSubmit();
    }

    const validate = () => {
        
    }

    const handleFieldChange = (name: string, value: string) => {
        setFormData({
            ...formData,
            [name]: value
        });
    }

    const context:FormContextT = {
        formData,
        handleFieldChange
    }

    return (
        <FormContext.Provider value={context}>
            <form 
                className={`form${className ? ' ' + className : ''}`}
                onSubmit={handlerSubmit}
            >
                {children}
            </form>
        </FormContext.Provider>
    )
}

Form.Field = FormField

Компонент FormField

import React, { useContext } from 'react';

import { FormContext } from './Form';

import { FormFieldProps } from './../../../types/form';

export const FormField = (props: FormFieldProps): JSX.Element => {

    const { name, children } = props;

    const formContext = useContext(FormContext);
    const { formData, handleFieldChange } = formContext;

    const fieldChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        handleFieldChange(name, e.target.value);

        if('onChange' in children.props) {
            children.props.onChange(e);
        }
    }

    console.log('re-render: ' + name);

    return (
        React.cloneElement(children, {
            name,
            onChange: fieldChange,
            value: formData[name]
        })
    );

};

Компонент Input

export const Input = (props: PropsTypes) => {

    const { className, value, name, placeholder, disabled, onChange, type = 'text' } = props;

    console.log('re-render-input: ' + name);

    return (
        <input
            type={type}
            name={name!}
            value={value!}
            placeholder={placeholder!}
            disabled={disabled!}
            className={`input${className ? ' ' + className : ''}`}
            onChange={onChange!}
        />
    )
}

Все значения полей формы записываются в объект formData в формате {поле: значение} в компоненте Form и через React Context передаются в FormField. Проблема в том, что при перезаписи значения поля обновляется formData в родительском компоненте, и перерендериваются все дочерние FormField. Подскажите, как сделать, чтобы перерендеривался только тот дочерний, который был изменен. Пытался использовать хук UseMemo, но не смог его правильно применить.


Ответы (0 шт):