头图

React hooks are really easy to use, and the code is simpler than class components, but sometimes it is inconvenient to update the data of useState, such as when declaring an array or an object, you have to set it up Pass a function back and use the spread operator to combine objects

setValue((oldValue) => ({
  ...oldValue,
  ...newValue,
}));

I feel that it is not very beautiful to look at in the component, and if the component code is a little more, it takes three lines to update the data, especially when it is used in if/for or callback. A simple encapsulation makes it more elegant when updating data in components.

First write several utility functions isArray, isObject, isNotObject

function isArray(value) {
  return value instanceof Array;
}

function isObject(value) {
  return value instanceof Object && !(value instanceof Array);
}

function isNotObject(value) {
  return typeof value !== "object";
}

Then in our custom hook function useSetState, declare the variable with the original useState, the variable can be returned directly, just do some operations on _setValue to return a new setValue.

In setValue, if initValue is an array, the new setValue is pushed when a single value is passed in, and merged when passing in an array; if initValue is an object, the incoming objects are merged, and an error is thrown when other types are passed in.

import { useState } from "react";

export default function useSetState(initValue) {
  const [_value, _setValue] = useState(initValue);

  function setValue(newValue) {
    // 初始数据为 数组
    if (isArray(initValue)) {
      if (isArray(newValue)) {
        _setValue((oldValue) => [...oldValue, ...newValue]);
      } else {
        _setValue((oldValue) => [...oldValue, newValue]);
      }
    }
    // 初始数据为 对象
    else if (isObject(initValue)) {
      if (isObject(newValue)) {
        _setValue((oldValue) => ({
          ...oldValue,
          ...newValue,
        }));
      } else {
        throw new Error(`${JSON.stringify(newValue)} 与初始数据类型不符!`);
      }
    } else if (isNotObject(initValue)) {
      _setValue(newValue);
    }
  }
  return [_value, setValue];
}

Actual use effect

const [obj, setObj] = useSetState({
    a: 1,
    b: 2,
  });

const [arr, setArr] = useSetState([{ id: 1 }, { id: 2 }]);

setObj({ c: 3 }); // {a: 1, b: 2, c: 3}
setArr({ id: 3 }); // [{ id: 1 }, { id: 2 },{ id: 3 }]

shellingfordly
87 声望14 粉丝

普通前端程序员