react学习笔记-04 —— React Hooks

Hooks就是在不编写class的情况下使用state等其他的React特性。

Hook 简介 – React

  1. 只能在 [ 函数最顶层 ] 调用Hook。
  2. 只能在 [ React的函数组件 ] 中调用Hook,不能在普通函数 也不能是class组件。

useState()


使用

import { useState } from "react";

function UseState() {
    const [stu, setStudent] = useState({ count: 0, age: 18 });
    const [search, setSearch] = useState(0);
    function add() {
        setSearch(search + 1)
    }
    function sub() {
        setSearch(search - 1)
    }
    return (
        <div>
            <button onClick={add}>+</button>
            {search}
            <button onClick={sub}>-</button>
        </div>
    );
}
export default UseState

与class中的setState不同的是,不会合并state中的值。

import { useState } from "react";

function UseState() {
    const [stu, setStudent] = useState({ count: 0, age: 18 });
    const [search, setSearch] = useState(0);
    function add() {
        setStudent({
            ...stu,
            count: state.count + 1
        })
    }
    function sub() {
        setStudent({
            ...stu,
            count: state.count - 1
        })
    }
    return (
        <div>
            <button onClick={add}>+</button>
            {stu.count}
            <button onClick={sub}>-</button>

        </div>
    );
}
export default UseState

prevState

setCount(prevState=>prevState+10)

useEffect


用于实现类似生命周期。在刘阿龙年起完成布局与绘制好后传给useEffect的函数会延迟调用。所以它适合用于许多常见的 副作用场景。

副作用

纯函数 产生确定的输出,与执行次数和时间无关。

副作用 http请求、系统IO相关API、函数体内修改函数外变量、Date.now()等

使用

//只有第一个参数是函数的时候,刷新和加载组件的时候都会执行。 
useEffect(()=>{console.log("1")})

//第二个参数,传递的是一个空数组,只有执行初始化和卸载的代码,不触发更新。
useEffect(()=>{console.log("1")},[])

//第二个参数,传递有值的数组,当值改变的时候就会重新渲染组件。
useEffect(()=>{console.log("1")},[source])

执行顺序

useEffect(()=>{console.log("1")})
console.log('2');
useEffect(()=>{console.log("3")},[])
执行结果顺序为:2->1->3

useLayoutEffect


与useEffect的对比

useEffct执行顺序:组件更新挂载完成->浏览器dom绘制完成->执行useEffect回调。

useLayoutEffect执行顺序:组件更新挂载完成->执行useLayoutEffect回调->浏览器dom绘制完成。

import React from 'react'

export default function useLayoutEffect() {
    const [count, setCount] = useState(0);
    useEffect(() => {
        console.log({ count });
        const pre = Data.now();
        // 等待了一秒
        while (Date.now() - pre < 1000) { }
        if (count === 0) {
            setCount(10 + Math.random() * 200);
        }
    }, [count])
    return (
        <div onClick={() => { setCount(0) }}>{count}</div>
    )
}

//可以发现会打印两次count,使用useEffect会闪烁


//改为useLayoutEffect就不会闪频
export default function useLayoutEffect() {
    const [count, setCount] = useState(0);
    useLayoutEffect(() => {
        console.log({ count });
        const pre = Data.now();
        // 等待了一秒
        while (Date.now() - pre < 1000) { }
        if (count === 0) {
            setCount(10 + Math.random() * 200);
        }
    }, [count])
    return (
        <div onClick={() => { setCount(0) }}>{count}</div>
    )
}

useRef


import React from 'react'

export default function useRef() {
    const inputRef = useRef(null);
    useEffect(() => {
        console.log(inputRef.current.value);
    })

    return (
        <input ref={inputRef} />
    )
}

useContext


在函数中可以使用context,解决了provider和consumer需要而外包装组件的问题。

使用

//平台
import React from 'react'

export default React.createContext();
//父组件
import React from 'react';
import Context from './context';
import Children from './Children';

export default function father() {
    const { Provider } = Context;
    return (
        <>
            <Provider value={{ userId: 1 }}>
                <Children />
            </Provider>
        </>
    )
}
//子组件
import React from 'react';
import ChildrenChildren from './ChildrenChildren'

export default function Children() {
    return (
        <div>Children
            <p>
                <ChildrenChildren />
            </p>
        </div>
    )
}
//子子组件
import React from 'react';
import context from './context';

export default function ChildrenChildren() {
    const fatherContext = useContext(context);
    console.log(fatherContext);
    return (
        <div>ChildrenChildren</div>
    )
}

 默认值

当父组件中没有加提供者<Provider value={{ userId: 1 }}></Provider>组件的时候
export default React.createContext({user:'默认值'});

useMemo | React.memo | useCallback


import { useState, useMemo, useEffect } from 'react'

export default function useMemo() {
    const [name, setName] = useState('小明');
    const [age, setAge] = useState(13);
    const [sex, setSex] = useState('man')
    return (
        <div>
            name: {name}-- age:{age} sex:--{sex}
            <button onClick={() => { setName(name + '加一') }}>changeName</button>
            <button onClick={() => { setAge(name + 1) }}>changeAge</button>
            <button onClick={() => { setSex(name + ' man') }}>changeSex</button>
            <br />
            <useMemoChild name={name} age={age} sex={sex} />
        </div>
    )
}


// 子组件
function useMemoChild({ name }) {
    useEffect(() => {
        console.log('子组件更新了');
    })
    return (
        <>
            <h2>这是子组件</h2>
            <p>{name}</p>
        </>
    )
}

我们可以发现父组件更新数据的时候,子组件会跟父组件一起更新。

但是就算子组件中没有传入的值改变时子组件也会再渲染,进行高开销计算。

useMemo

// 子组件
function useMemoChild({ name }) {
    useEffect(() => {
        console.log('子组件更新了');
    })

    const nameHandler = useMemo(() => {
        return name
    }, [name])

    return (
        <>
            <h2>这是子组件</h2>
            <p>{nameHandler}</p>
        </>
    )
}

 我们可以发现使用useMemo子组件不会改,但是useEffect会继续打印内容。

React.memo

const useMemoChild = React.memo(({ name }) => {
    useEffect(() => {
        console.log('子组件更新了');
    })
    return (
        <>
            <h2>这是子组件</h2>
            <p>{name}</p>
        </>
    )
})

useCallback

当子组件绑定事件的时候,由于函数的特性每次传过去的都是新的函数,所以需要使用到useCallback。

<useMemoChild onChange={()=>{}} />
export default function useMemo() {
    const [name, setName] = useState('小明');
    const [age, setAge] = useState(13);
    const [sex, setSex] = useState('man');
    const change = useCallback(() => { 
    },[name])
    return (
        <div>
            name: {name}-- age:{age} sex:--{sex}
            <button onClick={() => { setName(name + '加一') }}>changeName</button>
            <button onClick={() => { setAge(name + 1) }}>changeAge</button>
            <button onClick={() => { setSex(name + ' man') }}>changeSex</button>
            <br />
            <useMemoChild name={name} onClick={change} />
        </div>
    )
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值