1.概述
- 1.什么是Hook
- Hook 是 React 16.8 的新增特性,它可以让函数式组件拥有类组件特性;
- 2.为什么需要Hook
- 在Hook出现之前, 如果我们想在组件中保存自己的状态
- 如果我们想在组件的某个生命周期中做一些事情, 那么我们必须使用类组件
- 但是类组件的学习成本是比较高的, 你必须懂得ES6的class, 你必须懂得箭头函数
- 但是在类组件的同一个生命周期方法中, 我们可能会编写很多不同的业务逻辑代码
- 这样就导致了大量不同的业务逻辑代码混杂到一个方法中, 导致代码变得很难以维护
- 诸如: 在组件被挂载的生命周期中, 可能主要注册监听, 可能需要发送网络请求等
- 但是在类组件中共享数据是非常繁琐的, 需要借助Context或者Redux等
- 所以当应用程序变得复杂时, 类组件就会变得非常复杂, 非常难以维护
- 所以Hook就是为了解决以上问题而生的
- 3.如何使用Hook
- Hook的使用我们无需额外安装任何第三方库, 因为它就是React的一部分
- Hook只能在函数组件中使用, 不能在类组件,或者函数组件之外的地方使用
- Hook只能在函数最外层调用, 不要在循环、条件判断或者子函数中调用
2.useState
- 1.什么是Hook
- Hook就是一个特殊的函数
- 2.什么是useState Hook
- 可以让函数式组件保存自己状态(数据)的函数
- 3.useState Hook如何使用
- Hook只能在函数式组件中使用, 并且只能在函数体的最外层使用
- 4.useState函数
- 参数:保存状态的初始值
- 返回值:是一个数组, 这个数组中有两个元素
- 第一个元素:保存的状态
- 第二个元素:修改保存状态的方法
- 注意:不同组件中的 useState保存的状态是相互独立的, 是相互不影响的
import React, { useState } from 'react';
function App(){
// useState:
// 参数:保存状态的初始值
// 返回值:是一个数组,这个数组中有两个元素
// 第一个元素:保存的状态(数据)
// 第二个元素:修改保存状态的方法
const arr = useState(0);
const [state, setState] = arr;
return(
<div>
<p>{state}</p>
<button onClick={() => { setState(state + 1)}}>增加</button>
<button onClick={() => { setState(state - 1)}}>减少</button>
</div>
)
}
export default App;
- 5.useState 保存多个状态
import React, { useState } from 'react';
function App(){
// useState:
// 参数:保存状态的初始值
// 返回值:是一个数组,这个数组中有两个元素
// 第一个元素:保存的状态(数据)
// 第二个元素:修改保存状态的方法
// const arr = useState(0);
// const [state, setState] = arr;
// 注意点: 在同一个函数式组件中, 是可以多次使用同名的Hook的
const [ageState, setAgeState] = useState(18);
const [nameState, setNameState] = useState('lnj');
const [studentState, setStudentState] = useState({name: 'lnj', age: 16});
const [heroState, setHeroState] = useState([
{ id: 1, name: '鲁班' },
{ id: 2, name: '虞姬' },
{ id: 3, name: '黄忠' },
])
return(
<div>
<p>{ageState}</p>
<button onClick={() => { setAgeState(ageState + 1)}}>增加</button>
<button onClick={() => { setAgeState(ageState - 1)}}>减少</button>
<hr />
<p>{nameState}</p>
<button onClick={() => { setNameState('it') }}>修改</button>
<hr />
<p>{studentState.name}</p>
<p>{studentState.age}</p>
<hr />
<ul>
{
heroState.map((hero)=>{
return <li>{hero.name}</li>
})
}
</ul>
</div>
)
}
export default App;
- 6.useState 注意点
- 和类组件中的 setState 一样
import React, {useState} from 'react';
function App() {
const [ageState, setAgeState] = useState(18);
const [nameState, setNameState] = useState('lnj');
const [studentState, setStudentState] = useState({name:'zs', age:23});
const [heroState, setHeroState] = useState([
{id: 1, name:'鲁班'},
{id: 1, name:'虞姬'},
{id: 1, name:'黄忠'},
]);
function incrementAge() {
// setAgeState(ageState + 10);
// setAgeState(ageState + 10);
// setAgeState(ageState + 10);
setAgeState((preAgeState)=>preAgeState + 10);
setAgeState((preAgeState)=>preAgeState + 10);
setAgeState((preAgeState)=>preAgeState + 10);
}
function changeName() {
// studentState.name = 'it666';
setStudentState({...studentState, name:'it666'});
}
return (
<div>
<p>{ageState}</p>
<button onClick={()=>{incrementAge()}}>增加</button>
<button onClick={()=>{setAgeState(ageState - 1)}}>减少</button>
<hr/>
<p>{nameState}</p>
<button onClick={()=>{setNameState('it666')}}>修改</button>
<hr/>
<p>{studentState.name}</p>
<p>{studentState.age}</p>
<button onClick={()=>{changeName()}}>修改</button>
<hr/>
<ul>{
heroState.map((hero)=>{
return <li>{hero.name}</li>
})
}</ul>
</div>
)
}
export default App;
3.useEffect
- 1.什么是 useEffect Hook
- 可以把 useEffect Hook 看做
- componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个生命周期函数的组合
- 2.useEffect Hook 特点
- 可以设置依赖, 只有依赖发生变化的时候才执行
import React, { useEffect, useState } from 'react';
function Home(){
const [nameState, setNameState] = useState('lnj');
const [ageState, setAgeState] = useState(0);
// useEffect:相当于 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个生命周期函数的组合
// 第一个参数是一个函数
// 第二个参数是一个数组,用于指定依赖,只有依赖发生变化时才执行
useEffect(()=>{
// componentDidMount
// componentDidUpdate
console.log('组件被挂载或者组件更新完成');
return () => {
// componentWillUnmount
console.log('组件即将被卸载');
}
}, [nameState]);
return(
<div>
<p>{nameState}</p>
<button onClick={() => { setNameState('it666')}}>修改</button>
<p>{ageState}</p>
<button onClick={() => { setAgeState(ageState + 1)}}>增加</button>
<button onClick={() => { setAgeState(ageState - 1) }}>减少</button>
<hr />
</div>
)
}
function App(){
const [isShowState, setIsShowState] = useState(true);
return(
<div>
{/* 默认显示Home组件,点击切换隐藏组件 */}
{isShowState && <Home/>}
<button onClick={()=>{setIsShowState(!isShowState)}}>切换</button>
</div>
)
}
export default App;
- 3.useEffect Hook,对比 类组件生命周期方法 的优势
- 易于拆分
4.useContext
- 什么是 useContext Hook
- useContext 相当于 类组件中的 static contextType = Context
import React, { createContext, useContext } from 'react';
// 创建上下文对象
const UserContext = createContext({});
const ColorContext = createContext({});
function Home(){
const user = useContext(UserContext);
const color = useContext(ColorContext);
return(
<div>
{/* 消费数据 */}
<p>{user.name}</p>
<p>{user.age}</p>
<p>{color.color}</p>
</div>
)
}
function App(){
return(
// 生产数据
<UserContext.Provider value={{ name: 'lnj', age: 18 }}>
<ColorContext.Provider value={{ color: 'red' }}>
<Home />
</ColorContext.Provider>
</UserContext.Provider>
)
}
export default App;
5.useReducer
- useReducer函数
- 参数
- 第一个参数:处理数据的函数
- 第二个参数:保存的默认值
- 返回值
- 会返回一个数组, 这个数组中有两个元素
- 第一个元素:保存的数据
- 第二个元素:dispatch函数
- 会返回一个数组, 这个数组中有两个元素
- 参数
import React, { useReducer } from 'react';
// 定义reducer函数
function reducer(state, action){
switch (action.type){
case 'ADD':{
return{...state, num: state.num + 1 }
}
case 'SUB':{
return { ...state, num: state.num - 1 }
}
default:
return state;
}
}
function Home(){
/*
useReducer:
参数:
第一个参数: 处理数据的函数
第二个参数: 保存的默认值(对象)
返回值:会返回一个数组, 这个数组中有两个元素
第一个元素: 保存的数据
第二个元素: dispatch函数
* */
const [state, dispatch] = useReducer(reducer, {num: 0});
return(
<div>
<p>{state.num}</p>
{/* dispatch:派发任务 */}
<button onClick={()=>{dispatch({type: 'ADD'})}}>增加</button>
<button onClick={()=>{dispatch({type: 'SUB'})}}>减少</button>
</div>
)
}
function About() {
const [state, dispatch] = useReducer(reducer, { num: 5 });
return (
<div>
<p>{state.num}</p>
<button onClick={() => { dispatch({ type: 'ADD' }) }}>增加</button>
<button onClick={() => { dispatch({ type: 'SUB' }) }}>减少</button>
</div>
)
}
function App() {
return (
<div>
<Home />
<About />
</div>
)
}
export default App;
6.useCallback
- 什么是 useCallback Hook
- useCallback用于优化代码, 可以让对应的函数只有在依赖发生变化时才重新定义
- 当前Home和About重新渲染的原因是因为
- 父组件中的数据发生了变化, 会重新渲染父组件
- 重新渲染父组件, 就会重新执行父组件函数
- 重新执行父组件函数, 就会重新定义increment/decrement
- 既然increment/decrement是重新定义的, 所以就和上一次的不是同一个函数了
- 既然不是同一个函数, 所以Home和About接收到的内容也和上一次的不一样了
- 既然接收到的内容和上一次不一样了, 所以就会重新渲染
import React, { useState, memo, useCallback } from 'react';
function Home(props) {
console.log('Home被渲染了');
return (
<div>
<p>Home</p>
<button onClick={() => { props.handler() }}>增加</button>
</div>
)
}
function About(props) {
console.log('About被渲染了');
return (
<div>
<p>About</p>
<button onClick={() => { props.handler() }}>减少</button>
</div>
)
}
// memo:优化代码,只有父组件数据发生变化时,子组件不会重新渲染
const MemoHome = memo(Home);
const MemoAbout = memo(About);
function App() {
console.log('App被渲染了');
const [numState, setNumState] = useState(0);
const [countState, setCountState] = useState(0);
function increment() {
setNumState(numState + 1);
}
// function decrement() {
// setCountState(countState - 1);
// }
// useCallback:优化代码,只要countState没有发生变化, 那么useCallback返回的永远都是同一个函数
const decrement = useCallback(() => {
setCountState(countState - 1);
}, [countState]);
return (
<div>
<p>numState = {numState}</p>
<p>countState = {countState}</p>
{/*<button onClick={()=>{increment()}}>增加</button>*/}
{/*<button onClick={()=>{decrement()}}>减少</button>*/}
<MemoHome handler={increment} />
<MemoAbout handler={decrement} />
</div>
)
}
export default App;
7.useMemo
- 什么是 useMemo Hook
- useMemo 用于优化代码, 可以让对应的函数只有在依赖发生变化时才返回新的值
// useMemo: 只要countState没有发生变化, 那么useMemo返回的永远都是同一个值
const decrement = useMemo(()=>{
return ()=>{
setCountState(countState - 1);
};
}, [countState]);
- useCallback 和 useMemo 区别
- useCallback:返回的永远是一个函数
- useMemo:返回的是 return 返回的内容
import React, {useState, memo, useCallback, useMemo} from 'react';
function Home(props) {
console.log('Home被渲染了');
return (
<div>
<p>Home</p>
<button onClick={()=>{props.handler()}}>增加</button>
</div>
)
}
function About(props) {
console.log('About被渲染了');
return (
<div>
<p>About</p>
<p>{props.user.name}</p>
<p>{props.user.age}</p>
</div>
)
}
const MemoHome = memo(Home);
const MemoAbout = memo(About);
function App() {
console.log('App被渲染了');
const [numState, setNumState] = useState(0);
function increment() {
setNumState(numState + 1);
}
// const user = {name: 'lnj', age:18};
const user = useMemo(()=>{
return {name: 'lnj', age:18};
}, []);
return (
<div>
<p>numState = {numState}</p>
<MemoHome handler={increment}/>
<MemoAbout user={user}/>
</div>
)
}
export default App;
useMemo应用场景:提升性能
// 定义一个函数, 模拟耗时耗性能操作
function calculate() {
console.log('calculate被执行了');
let total = 0;
for(let i = 0; i < 999; i++){
total += i;
}
return total;
}
function App() {
console.log('App被渲染了');
const [numState, setNumState] = useState(0);
// const total = calculate();
// useMemo:提升性能,让calculate函数只调用一次
const total = useMemo(()=>{
return calculate();
}, []);
return (
<div>
<p>{total}</p>
<p>{numState}</p>
<button onClick={()=>{setNumState(numState + 1)}}>增加</button>
</div>
)
}
export default App;