react Пример обработчика сложных состояний формы, вложенных массивов объектов (с использованием immer)

Пример хелпера, который определяет обработчики полей и также функцию изменения и получения состояния (функция получение в отличии от объекта стейта не меняется и её оказывается предпочтительнее использовать в зависимостях колбека при мемоизации):

import React from 'react';
import dot from 'dot-object';
import produce from "immer";

/**
 * 
 * @param {objecr} formState 
 * @param {function} setFormState 
 * @param {object} settings  пример:
 *     {defaultStates: // отвечает за добавление значений в массив
 *          {phoneNumber: {....}, contact: {...}}
 *     }
 */


function FromStateHelper(initialState, settings) {
    const { current: it } = React.useRef({});

    const reducer = React.useMemo(() => {
        const innerProduce = produce((formState, action) => {
            
            const { type, evt } = action;

            // console.log('test value',  evt && evt.target.value);

            switch (type) {
                case 'handleChangeText':
                    dot.str(evt.target.name, evt.target.value, formState);
                    break;
                case 'handleChangeInt':
                    dot.str(evt.target.name, parseInt(evt.target.value), formState);
                    break;

                case 'handleChangeBool':
                    console.log('handleChangeBool', evt.target.name);
                    dot.str(evt.target.name, (evt.target.value === 'true'), formState);
                    break;

                case 'handlePushDefaultElementInArray': {
                    if (typeof evt.preventDefault === "function") {
                        evt.preventDefault();
                    }
                    let arr = dot.pick(evt.target.name, formState);
                    arr.push({ ...settings.defaultStates[evt.target.dataset['stateName']] });
                    break;
                }
                case 'handleRemoveElementFromArray': {
                    if (typeof evt.preventDefault === "function") {
                        evt.preventDefault();
                    }
                    let arr = dot.pick(evt.target.name, formState);
                    arr.splice(evt.target.dataset['arrayIndex'], 1);
                    break;
                }
                case 'setState':
                    return action.state;
            }
        });
        return function innerREducer(...args) {
            return innerProduce(...args);
        }
    }, [settings]);

    const [formState, dispatch] = React.useReducer(reducer, initialState);
    // console.log(formState)

    const handleChangeBool = React.useCallback((evt) => {
        dispatch({ type: 'handleChangeBool', evt: evt.nativeEvent });
    }, [dispatch]);

    const handleChangeText = React.useCallback((evt) => {
        //window.testValue = 'test value';
        dispatch({ type: 'handleChangeText', evt: evt.nativeEvent });
        window.testValue = null;
    }, [dispatch]);

    const handleChangeInt = React.useCallback((evt) => {
        dispatch({ type: 'handleChangeInt', evt: evt.nativeEvent });
    }, [dispatch]);

    const handlePushDefaultElementInArray = React.useCallback((evt) => {

        dispatch({ type: 'handlePushDefaultElementInArray', evt: evt.nativeEvent });
        
    }, [dispatch]);

    const handleRemoveElementFromArray = React.useCallback((evt) => {
        dispatch({ type: 'handleRemoveElementFromArray', evt: evt.nativeEvent });
    }, [dispatch]);

    const setFormState = React.useCallback(state => {
        dispatch({ type: 'setState', state });
    }, [dispatch]);

    const getFormState = React.useCallback(state => {
        return it.formState;
    }, []);

    Object.assign(it, {
        getFormState,
        formState,
        setFormState,
        handleChangeBool,
        handleChangeText,
        handleChangeInt,
        handlePushDefaultElementInArray,
        handleRemoveElementFromArray,
    });

    return it;
}

export default FromStateHelper;

Key Words for FKN + antitotal forum (CS VSU):