Hook 函数

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;

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值