支持多级绑定。

    参考:

    依赖

    1. yarn add immer lodash

    form-state.js

    1. import React from "react";
    2. import produce from "immer"
    3. import set from "lodash/set";
    4. import has from "lodash/has";
    5. // eslint-disable-next-line consistent-return
    6. const enhancedReducer = (state, updateArg) => {
    7. // check if the type of update argument is a callback function
    8. if (updateArg.constructor === Function) {
    9. return {...state, ...updateArg(state)};
    10. }
    11. // if the type of update argument is an object
    12. if (updateArg.constructor === Object) {
    13. // does the update object have _path and _value as it's keys
    14. // if yes then use them to update deep object values
    15. if (has(updateArg, "_path") && has(updateArg, "_value")) {
    16. const {_path, _value} = updateArg;
    17. return produce(state, draft => {
    18. set(draft, _path, _value);
    19. });
    20. }
    21. return {...state, ...updateArg};
    22. }
    23. };
    24. const useFormState = initialState => {
    25. const [state, updateState] = React.useReducer(enhancedReducer, initialState);
    26. const updateForm = React.useCallback(({target: {value, name, type}}) => {
    27. const updatePath = name.split(".");
    28. // if the input is a checkbox then use callback function to update
    29. // the toggle state based on previous state
    30. if (type === "checkbox") {
    31. updateState(prevState => ({
    32. [name]: !prevState[name]
    33. }));
    34. return;
    35. }
    36. // if we have to update the root level nodes in the form
    37. if (updatePath.length === 1) {
    38. const [key] = updatePath;
    39. updateState({
    40. [key]: value
    41. });
    42. }
    43. // if we have to update nested nodes in the form object
    44. // use _path and _value to update them.
    45. if (updatePath.length === 2) {
    46. updateState({
    47. _path: updatePath,
    48. _value: value
    49. });
    50. }
    51. }, []);
    52. return [state, updateState,updateForm];
    53. };
    54. export default useFormState;

    使用

    1. import useFormState from "./form-state";
    2. const initialState = {
    3. fname: "",
    4. lname: "",
    5. email: "",
    6. message: ""
    7. };
    8. const [state, updateState,updateForm] = useFormState(initState);
    9. state 表示表单
    10. updateState 用来手动更新state
    11. updateForm 自动双向绑定

    绑定示例:

    image.png