你好,你有没有问过为什么现在从函数中返回数组成为一种趋势?
我们都知道,像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;
我们可以看到,当使用自定义钩子时,我们没有看到我们的组件有任何代码重复,这是因为有两个原因...
- 自定义钩子对于在一个简单的函数中提取组件的逻辑是非常好的,它也使得我们的逻辑可以在任何其他的输入中重复使用。
- 返回数组使我们更容易、更干净地解构数值,我们只给返回的数组元素命名。
如果我们决定返回对象而不是数组,我们的组件将看起来像这样
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个元素,在这种情况下维护代码也会非常困难,所以返回数组并不总是一个正确的决定。
谢谢你!