Hooks
Hook 是React 16.8的新特性,他可以让你在 function 组件中使用 state 以及其他的 React 特性。
Hooks的特点:
- 使你在无需修改组件结构的情况下复用状态逻辑
 - 可将组件中相互关联的部分拆分成更小的函数,复杂组件将变得更容易理解
 - 更简洁、更易理解代码
 
Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:
- 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用
 - 只能在 React 的函数组件中调用 Hook
useState
useState(initialState) 接收初始状态,返回一个由状态和更新函数组成的数组
 
import React, { useState } from 'react';// 声明列表组件function FruitList ({ fruits, onSetFruit }) {return (<ul>{ fruits.map(item => <li onClick={ () => onSetFruit(item)} key={item}>{item}</li>) }</ul>)}// 声明输入组件function FruitAdd (props) {const [pname, setPname] = useState("") // 键盘事件处理const onAddFruit = e => {if (e.key === "Enter") {props.onAddFruit(pname);setPname("");}}return (<div><inputplaceholder="请输入需要添加的水果"type="text"value={pname}onChange={e => setPname(e.target.value)}onKeyDown={onAddFruit}/></div>)}export default function HooksTest() {// useState(initialState) 接收初始状态,返回一个由状态和更新函数组成的数组const [fruit, setFruit] = useState("")const [fruits, setFruits] = useState(['香蕉', '草莓', '芒果'])return (<div><p>{ fruit === "" ? "请选择喜爱的水果" : `你的的选择是:${fruit}` }</p><FruitList fruits={fruits} onSetFruit={setFruit}></FruitList><FruitAdd onAddFruit={pname => setFruits([...fruits, pname])}></FruitAdd></div>);}
useEffect
useEffect 给函数组件增加了执行副作用操作的能力。
副作用(Side Effect)是指一个 function 做了和本身运算、返回值无关的事,比如:修改了全局变量、修改了传入的 参数、甚至是 console.log(),所以 ajax 操作,修改 dom 都是算作副作用。
- 异步获取数据 ```javascript import { useEffect } from “react”;
 
useEffect(()=>{ setTimeout(() => { setFruits([‘香蕉’,’西瓜’]) }, 1000); },[]) // 设置空数组意为没有依赖,则副作用操作仅执行一次
如果副作用对某状态有依赖,需要添加依赖选项```javascriptuseEffect(() => {document.title = fruit;}, [fruit]);
清除工作:有一些副作用是需要清除的,清除工作非常重要,可以防止内存泄漏
useEffect(() => {const timer = setInterval(() => {console.log('msg')}, 1000)// 返回一个清理函数,组件卸载后会执行清理函数return function () {clearInterval(timer)}})
useReducer
useReducer是useState的可选项,常用于组件有复杂状态逻辑时,类似于redux中reducer概念。
范例:使用 useReducer 改写上面的代码
import React, { useState, useEffect, useReducer } from 'react';function FruitList ({ fruits, onSetFruit }) {return (<ul>{ fruits.map(item => <li onClick={ () => onSetFruit(item)} key={item}>{item}</li>) }</ul>)}// 声明输入组件function FruitAdd (props) {const [pname, setPname] = useState("") // 键盘事件处理const onAddFruit = e => {if (e.key === "Enter") {props.onAddFruit(pname);setPname("");}}return (<div><inputplaceholder="请输入想要添加的水果"type="text"value={pname}onChange={e => setPname(e.target.value)}onKeyDown={onAddFruit}/></div>)}// 添加fruit状态维护fruitReducerfunction fruitReducer (state, action) {switch(action.type) {case "init":return action.payloadcase "add":return [...state, action.payload]default:return state}}export default function HooksTest() {// useState(initialState) 接收初始状态,返回一个由状态和更新函数组成的数组const [fruit, setFruit] = useState("")// 接收一个 reducer 和初始值,返回 state 和 dispatchconst [fruits, dispatch] = useReducer(fruitReducer, [])// useEffect 接收回调函数和一个依赖数组(依赖为空时,useEffect函数只执行一次)useEffect(() => {setTimeout(() => {// setFruits(['香蕉', '草莓', '芒果'])dispatch({ type: 'init', payload: ['香蕉', '草莓', '芒果']})}, 1000)}, [])// 如果副作用操作对某状态有依赖,需要添加依赖选项useEffect(() => {document.title = fruit; },[fruit]);// 清除工作:有一些副作用是需要清除的,清除工作非常重要,可以防止内存泄漏useEffect(() => {const timer = setInterval(() => {console.log('msg')}, 1000)// 返回一个清理函数,组件卸载后会执行清理函数return function () {clearInterval(timer)}})return (<div><p>{ fruit === "" ? "请选择喜爱的水果" : `你的的选择是:${fruit}` }</p><FruitList fruits={fruits} onSetFruit={setFruit}></FruitList><FruitAdd onAddFruit={pname => dispatch({ type: 'add', payload: pname })}></FruitAdd></div>);}
useContext
useContext用于在快速在函数组件中导入上下文,useContext可以实现组件之间的解耦,复杂组件会更变得更加容易理解。
import React, { useState, useEffect, useReducer, useContext } from 'react';function FruitList ({ fruits, onSetFruit }) {return (<ul>{ fruits.map(item => <li onClick={ () => onSetFruit(item)} key={item}>{item}</li>) }</ul>)}// 声明输入组件function FruitAdd (props) {// 使用 useContent 获取上下文const { dispatch } = useContext(Context)const [pname, setPname] = useState("") // 键盘事件处理const onAddFruit = e => {if (e.key === "Enter") {// props.onAddFruit(pname);dispatch({ type: 'add', payload: pname })setPname("");}}return (<div><inputplaceholder="请输入想要添加的水果"type="text"value={pname}onChange={e => setPname(e.target.value)}onKeyDown={onAddFruit}/></div>)}// 添加fruit状态维护fruitReducerfunction fruitReducer (state, action) {switch(action.type) {case "init":return action.payloadcase "add":return [...state, action.payload]default:return state}}// 创建上下文对象const Context = React.createContext()export default function HooksTest() {// useState(initialState) 接收初始状态,返回一个由状态和更新函数组成的数组const [fruit, setFruit] = useState("")// const [fruits, setFruits] = useState([])// 接收一个 reducer 和初始值,返回 state 和 dispatchconst [fruits, dispatch] = useReducer(fruitReducer, [])// useEffect 接收回调函数和一个依赖数组(依赖为空时,useEffect函数只执行一次)useEffect(() => {setTimeout(() => {// setFruits(['香蕉', '草莓', '芒果'])dispatch({ type: 'init', payload: ['香蕉', '草莓', '芒果']})}, 1000)}, [])// 如果副作用操作对某状态有依赖,需要添加依赖选项useEffect(() => {document.title = fruit; },[fruit]);// 清除工作:有一些副作用是需要清除的,清除工作非常重要,可以防止内存泄漏useEffect(() => {const timer = setInterval(() => {console.log('msg')}, 1000)// 返回一个清理函数,组件卸载后会执行清理函数return function () {clearInterval(timer)}})return (<Context.Provider value={{ fruits, dispatch }}><div><p>{ fruit === "" ? "请选择喜爱的水果" : `你的的选择是:${fruit}` }</p><FruitList fruits={fruits} onSetFruit={setFruit}></FruitList><FruitAdd></FruitAdd></div></Context.Provider>);}
