为什么useState钩子返回数组而不是对象?

117 阅读3分钟

你好,你有没有问过为什么现在从函数中返回数组成为一种趋势?

我们都知道,像useState、useEffect或useRef这样的react钩子只能在组件的顶层使用,不能在函数中使用,自定义钩子是我们可以在其中使用React钩子的函数。

让我们看看没有使用自定义钩子的例子 ...

import React, { useState, useEffect } from "react";

const Form = () => {
  const [name, setName] = useState(
    JSON.parse(localStorage.getItem("name")) ?? ""
  );
  const [email, setEmail] = useState(
    JSON.parse(localStorage.getItem("email")) ?? ""
  );

  useEffect(() => {
    localStorage.setItem("name", JSON.stringify(name));
  }, [name]);
  useEffect(() => {
    localStorage.setItem("email", JSON.stringify(email));
  }, [email]);
  return (
    <form>
      <input type="text" value={name} onChange={e => setName(e.target.value)} />
      <input
        type="text"
        value={email}
        onChange={e => setEmail(e.target.value)}
      />
      <button>Register</button>
    </form>
  );
};

export default Form;

所以,我们有一个包含两个输入的react组件,目标是将用户的输入保存在localStorage中,当他回来时再取回。

所以我们为每个输入设置了一个状态,它由存储的值或空字符串初始化,在改变时我们用新的值来设置状态,并且我们有一个useEffect来在改变时将值设置到localStorage。

这很好,但让我们用自定义钩子建立同样的例子,看看有什么不同......

import { useState, useEffect } from "react";

export default function useStoreInput(storageKey) {
  const [value, setValue] = useState(
    JSON.parse(localStorage.getItem(storageKey)) ?? ""
  );

  useEffect(() => {
    localStorage.setItem(storageKey, JSON.stringify(value));
  }, [value, storageKey]);

  return [value, setValue];
}

这是我们的自定义钩子,它是一个使用React钩子的普通函数,我们把localStorage的键名传给它,它为我们定义了一个状态,并像以前一样用localStorage的值初始化它,然后它监听这个状态并在变化时把它存储到localStorage。

正如我们所看到的,我们选择了返回数组[value, setValue]而不是一个对象,我们将看到为什么...

让我们看看我们的组件使用我们新的自定义钩子 ...

import React from "react";
import useStoreInput from "./useStoreInput";

const Form = () => {
  const [name, setName] = useStoreInput("name");
  const [email, setEmail] = useStoreInput("email");

  return (
    <form>
      <input type="text" value={name} onChange={e => setName(e.target.value)} />
      <input
        type="text"
        value={email}
        onChange={e => setEmail(e.target.value)}
      />
      <button>Register</button>
    </form>
  );
};

export default Form;

我们可以看到,当使用自定义钩子时,我们没有看到我们的组件有任何代码重复,这是因为有两个原因...

  1. 自定义钩子对于在一个简单的函数中提取组件的逻辑是非常好的,它也使得我们的逻辑可以在任何其他的输入中重复使用。
  2. 返回数组使我们更容易、更干净地解构数值,我们只给返回的数组元素命名。

如果我们决定返回对象而不是数组,我们的组件将看起来像这样

import React from "react";
import useStoreInput from "./useStoreInput";

const Form = () => {
  const { value: name, setValue: setName } = useStoreInput("name");
  const { value: email, setValue: setEmail } = useStoreInput("email");

  return (
    <form>
      <input type="text" value={name} onChange={e => setName(e.target.value)} />
      <input
        type="text"
        value={email}
        onChange={e => setEmail(e.target.value)}
      />
      <button>Register</button>
    </form>
  );
};

export default Form;

所以每次我使用钩子时,我都会告诉它用新的名字重命名value和setValue。

这正是为什么 ***useState()***钩子返回数组而不是对象

const [counter, setCounter] = useState(0);

所以react的创造者选择了从钩子返回数组,以使其更容易对返回的数组进行重组并定义新的状态。

这不仅仅是关于钩子或React,甚至是JavaScript,如果你使用一种支持去结构化的语言,你也可以这样想。

返回数组是非常棒的,但可以肯定的是,这取决于你的情况,让我们假设如果我们有一个返回10个属性的函数,但我们并不总是使用所有的属性,在某些情况下,我们只使用第8个元素,在这种情况下维护代码也会非常困难,所以返回数组并不总是一个正确的决定。

谢谢你!