我是靠谱客的博主 外向毛衣,最近开发中收集的这篇文章主要介绍React Hook,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

 1. 为什么使用 hook

class 组件中的 this 难以理解,且 class 不能很好的压缩,并且会使热重载出现不稳定的情况。

所以 hook 就为解决这些问题而来:

避免地狱式嵌套,可读性提高。

函数式组件,比 class 更容易理解。

class 组件生命周期太多太复杂,使函数组件存在状态。

解决 HOC 和 Render Props 的缺点。

UI 和 逻辑更容易分离

2. Hook的一些API

我来介绍一下,hook的一些常用的api

2.1 useState

使用状态    

const [data,setData] = useState("默认值")

注意事项 1:不可局部更新

如果 state 是一个对象,能否部分 setState?

答案是不行,因为 setState 不会帮我们合并属性

那么 useReducer 会合并属性吗?也不会!

因为 React 认为这应该是你自己要做的事情

注意事项 2:地址要变

setState(obj)如果 obj 地址不变,那么 React 就认为数据没有变化,不会更新视图

useState 接受函数

const [state, setState] = useState(() => {return initialState}) //该函数返回初始 state,且只执行一次

2.2 useReducer

用来践行 Flux/Redux 思想

一、创建初始值 initialState

二、创建所有操作 reducer(state, action)

三、传给 userReducer,得到读和写 API

四、调用写({type:"操作类型"})

如何代替 Redux

一、将数据集中在一个 store 对象

二、将所有操作集中在 reducer

三、创建一个 Context

四、创建对数据的读取 API

五、将第四步的内容放到第三步的 Context

六、用 Context.Provider 将 Context 提供给所有组件

七、各个组件用 useContext 获取读写 API

2.3 useContext

全局变量是全局的上下文

上下文是局部的全局变量

使用方法

一、使用 C = createContext(initial) 创建上下文

二、使用 <C.Provider> 圈定作用域

三、在作用域内使用 useContext(C)来使用上下文

2.3 useEffect

副作用

对环境的改变即为副作用,如修改 document.title

但我们不一定非要把副作用放在 useEffect 里面

实际上叫做 afterRender 更好,每次 render 后执行

用途

一、作为 componentDidMount 使用,[ ] 作第二个参数

二、作为 componentDidUpdate 使用,可指定依赖

三、作为 componentWillUnmount 使用,通过 return

四、以上三种用途可同时存在

// 作为 componentDidMount 使用,[] 作为第二个参数
useEffect(() => {
    console.log("第一次渲染执行这句话");
}, []); // [] 里面的变量变化时执行 => 不会执行
// 作为 componentDidUpdate 使用,可指定依赖 n
useEffect(() => {
    console.log("n变化时执行这句话");
}, [n]); // n 变化时执行
useEffect(() => {
    console.log("任何一个state变化时都会执行");
});
// 作为 componentDidUpdate 使用,可指定依赖 n
useEffect(() => {
    const timer = setInterval(() => {
        console.log("hi");
    }, 1000);
    return () => {
        setTimeout(() => {
            window.clearInterval(timer);
        }, 10000);
    };
},[]);

特点

如果同时存在多个 useEffect,会按照出现次序执行

2.4 useLayoutEffect

布局副作用

useEffect 在浏览器渲染完成后执行

useLayoutEffect 在浏览器渲染前执行

特点

useLayoutEffect 总比 useEffect 先执行

useLayoutEffect 里的任务最好影响了 Layout

/* useLayoutEffect比useEffect先执行 */
function App2() {
    const [n, setN] = useState(0)
    const onClick = () => {
        setN(i => i + 1)
    }
    //执行顺序打印出 2、3、1
    useEffect(() => {
        console.log(1)
    })
    useLayoutEffect(() => {
        console.log(2)
    })
    useLayoutEffect(() => {
        console.log(3)
    })
    return (
        <div className="App">
            <h1>n: {n}</h1>
            <button onClick={onClick}>Click</button>
        </div>
    );
}

经验

为了用户体验,优先使用 useEffect (优先渲染)

2.5 useMemo

特点

第一个参数是 () => value

第二个参数是依赖 [m, n]

只有当依赖变化时,才会计算出新的 value

如果依赖不变,那么就重用之前的 value

这不就是 Vue 2 的 computed 吗?

注意

如果你的 value 是一个函数,那么你就要写成 useMemo(() => x => console.log(x))

这是一个返回函数的函数

是不是很难用?于是就有了 useCallback

2.6 useCallback

用法

useCallback(x => console.log(x), [m]) 等价于

useMemo( () => x => console.log(x), [m])

2.7 forwardRef

useRef

可以用来引用 DOM 对象

也可以用来引用普通对象

forwardRef

props 无法传递 ref 属性

function App(){
    const buttonRef = useRef(null)
    return (
        <div>
            <Button ref={buttonRef}>按钮</Button>
            {/* 控制台报错:
                    Warning: Function components cannot be given refs.
                Attempts to access this ref will fail.
                Did you mean to use React.forwardRef()?
            */}
        </div>
    )
}

const Button = (props) => {
    console.log(props) // {ref: undefined, children: "按钮"}
    return <button {...props} />
}

实现 ref 的传递:由于 props 不包含 ref,所以需要 forwardRef

import React, {forwardRef, useRef} from 'react';
function App(){
    const buttonRef = useRef(null)
    return (
        <div>
            <Button ref={buttonRef}>按钮</Button2>
        </div>
    )
}
const Button = forwardRef((props, ref) => {
    console.log(ref)  //可以拿到ref对button的引用,forwardRef仅限于函数组件,class 组件是默认可以使用 ref 的
    return <button ref={ref} {...props} />;
})

最后

以上就是外向毛衣为你收集整理的React Hook的全部内容,希望文章能够帮你解决React Hook所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部