在 react 的开发过程中,相信大家都会遇到一些问题,比如:组件的复用,复杂组件的嵌套传值,以及表现在 HTML 上面的多余标签嵌套等等,当然解决问题的办法大家都有。但是可能不是很好用,那么 react 就在 16.8.0 版本为大家增加了一个 Hook 特性用于解决某些问题。大家在使用前,需要将 react 提升至 16.8.0 版本或更新的版本
学习之前
在react文档中,这样写到“ Hooks solve a wide variety of seemingly unconnected problems in React that we’ve encountered over five years of writing and maintaining tens of thousands of components.” Hooks解决了五年来各种不相关的问题,我不知道有没有夸张的成分,但是Hooks 确实在更新并完善着 react ,呐。既然更新了。那么就要去学习
Hook对于State的改变
在React 中组件分为有状态组件(class)和无状态组件(function),有状态组件有着生命周期方法和状态(state)。而无状态组件则没有这些。React的思想是把页面拆成单独的可复用的组件,但是项目中各组件的沉重繁琐,它们有着各自独立的状态(state),想要复用这些组件就显得很麻烦。所以Hook 给无状态组件(function)带来了 状态方法(useState)和生命周期方法(useEffect)
声明State
Hook使用useState 来声明State,在使用useState 的时候,需要先引入React 的useState ,然后当你需要声明state 的时候在函数中使用useState 进行state 声明
import React,{useState} from 'react'
function useNext(){
// 声明一个叫“李四”的state,可以通过调用newName来更新当前的name
const [name,newName]=useState('李四')
}
注意:React 通过Hook 的调用顺序来将内部state 和Hook 进行关联,所以Hook 只能在组件的最顶层调用,如果有条件判断执行。可以放入Hook 里面进行判断
读取State
在函数中,可以直接使用state的名字来进行state读取
function useNext(){
// 声明一个叫“李四”的state,可以通过调用newName来更新当前的name
const [name,newName]=useState('李四')
return(
<p>你的名字是 {name} </p>
)
}
更新State
在Hook 中,我们需要使用useState 中声明的setState 来进行state更新
<input type="" name="" onchange={(e) => newName(e)}/>
Hook 对于生命周期的改变
在React 中,生命周期是很重要的一部分,我们常用的生命周期函数有 componentWillMount componentDidMount componentWillUpdate componentDidUpdate componentWillUnmount 等。当我们使用Hook 的时候,Hook 提供useEffect 让你在函数组件中执行side effects
在官方文档中
side effects
被翻译为副作用,我觉得翻译为 干涉操作 可能更好一点,That process of calling into the real world is what side-effects are. https://goshakkk.name/redux-side-effect-approaches/
不需要销毁的side effects
当我们需要在Dom更新后执行一些side effects ,如请求数据,切换显示等等,不需要销毁的的操作的时候,可以使用useEffect 来进行实现,useEffect 在默认情况下,它在第一次渲染之后和每次更新之后都会执行
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
}
如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可,如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
需要销毁的side effects
当组件卸载的时候,某些操作需要及时清理。防止内存泄漏的问题,我们也可以使用useEffect 来进行实现,useEffect 的设计是在同一个地方执行。如果你的 effect 返回一个函数,React 将会在执行清除操作时调用它,
在 React class 中,你通常会在 componentDidMount 中设置订阅,并在 componentWillUnmount 中清除它。例如,假设我们有一个 ChatAPI 模块,它允许我们订阅好友的在线状态。以下是我们如何使用 class 订阅和显示该状态
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// Specify how to clean up after this effect:
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
Effect 还有个目的是要解决 class 中生命周期函数经常包含不相关的逻辑,但又把相关逻辑分离到了几个不同方法中的问题,那么就需要使用到多个Effect Hook 来进行代码分离
function FriendStatusWithCounter(props) {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
// ...
}
文档参考
React 文档 https://reactjs.org/docs/hooks-intro.html
淘宝FED文章 http://taobaofed.org/blog/2018/11/27/hooks-and-function-component/