Hooks 是什么

官方文档很简单的介绍,可以不使用 class 来实现有状态的组件

为什么要引入 Hooks

  • 组件之间难以重用有状态的逻辑

虽然可以使用 render props 或者高阶组件来解决组件的重用问题,但是使用的时候我们需要把组件重构,这样会导致代码太笨重。如果使用太多的 HOC 会导致组件的层次结构很深。 https://github.com/facebook/react-devtools/pull/503,使用Hooks就可以从组件中提取有状态逻辑,以便对其进行独立测试并重用。Hooks允许我们在不更改组件层次结构的情况下重用有状态逻辑

  • 逻辑复杂的组件难以开发与维护,当我们的组件需要处理多个互不相关的 localstate 时,每个生命周期函数中可能会包含着各种互不相关的逻辑在里面

Hooks 的种类

Hooks 的分类有三种,分别是

  1. State Hook,定义 state 和 setState 方法
  2. Effect Hook,通过此 Hooks 操作获取数据的方法,可以看做是componentDidMountcomponentDidUpdatecomponentWillUnmont的合并
  3. Custom Hooks,自定义 Hooks 可以将组件逻辑提取到可重用函数中,使用 use 开头

State Hook

一个简单的栗子,声明一个Counter组件并使用useState来声明count状态和setCount函数,这里使用了数组的解构

第二个参数setCount可以使用任意的函数名,不一定是setCount,可以是setNumbersetSum...,为了规范一点使用 setCount

function Counter(props) {
// 声明一个 count 状态和 setCount 函数,useState(0) 参数表示默认值
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`mount didmount unmount and count = ${count}`);
return () => {
console.log('component unmount');
};
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}

接下来使用这个组件

class App extends Component {
render() {
return <div>{Counter()}</div>;
}
}

纳尼,报错了 Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)

意思是 Hooks 只能在函数组件使用,不能在 class 组件使用

ReactDOM.render(<Counter name="aa" />, document.getElementById('root'));

Effect Hook

Effect Hook 也就是一个集成了componentDidMountcomponentDidUpdatecomponentWillUnmont功能的函数

上面的栗子引入了State Hook,接下来引入 Effect Hook 到栗子 🍆 中

function Counter() {
// 声明一个 count 状态和 setCount 函数,useState(0) 参数表示默认值
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`mount didmount unmount and count = ${count}`);
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}

可以看到挂载和 click 的时候会触发useEffect函数

自定义 Hook

自定义 Hook 就是以use开头定义的 javascript 函数,比如在定义函数的时候,我们会把一些相同的逻辑封装成一个第三方函数,然后分别在其他函数使用,自定义 Hook 也是这个思想

举个栗子 🍆,我们需要在不同组件共享用户的登录状态,我们可以这样做

function useUserStatus(id) {
const [isLogin, setLogin] = useState(false);
useEffect(() => {
setLogin(id === 1);
});
return isLogin;
}
function LoginBar() {
const isLogin = useUserStatus(1);
return <div>Login bar component {isLogin ? '已登陆' : '未登陆'}</div>;
}
function App() {
const isLogin = useUserStatus(1);
return (
<div>
App component {isLogin ? '已登陆' : '未登陆'}
<LoginBar />
</div>
);
}

Hooks 规则

必须要在顶层使用 Hooks**,不要在循环,条件,嵌套函数使用 Hooks**

只从 React 函数调用 Hooks,不要在 js 函数调用 Hooks

总结

Hooks 其实就是以函数的思想来写类组件,不同的 Hooks 可以通过参数传递