由Vue转React的自学文档总结(二)

120 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情

前言

由vue3转学react,之前从未接触过react,自学了一遍感觉还好,容易上手。 期间的一些笔记,后续有更深的见解持续更新。

hooks的一些API

本质:让函数组件更强大更灵活的钩子,只能在函数组件(有状态)中使用。

作用:组件状态复用,class组件自身问题

注意:只能写在函数组件最外层,不能写在if,for循环判断里面(官文文档解释为react的运行机制要保持这些hooks的顺序的唯一性),可以将回调函数作为参数传递

useState

const [count, setCount] = useState(initCount);

useState传入的是当前count初始值也就是initCount(可以是初始值也可以是函数),然后返回的是最新的count,和一个修改count的方法(可以普通调用和函数调用,,数据是对象类型的话,一般要结合拓展运算符复制一份)。

//三种情况
setCount(count + 1)
setCount(() => count + 1)
setCount(() => {
    return{
        ...count,
        //再对象赋值
    }
})

初始值initCount只有在首次渲染生效,后续更新会被忽略,直接调用setCount

一句话:在同步里,异步更新状态和dom,在异步里,同步更新状态和dom。

useEffect:为更好处理副作用(除了更新UI外的作用,如ajax,本地存储)

感觉像vue的nextTick。

React会在每次渲染完后调用useEffect,包括第一次加载渲染DOM。

useEffect 设计初衷是用来取代 componentDidMount 和 componentDidUpdate,它接收两个参数(fun,[]),一个处理函数,另一个关联的状态或数组,这个变了就重新执行。

加 [ ] 为行业只执行义一次的默认写法,一般用于发送请求:

useEffect(() => {
  	async function sendData() {
  		const res = await fetch('http://www.baidu.com')
        .then(response => response.json())
        .then(data => console.log(data))
  	}
    sendData()
},[])

useLayoutEffect 的作用和 useEffect 几乎差不多,几乎看不到任何差别,但它们的渲染底层逻辑就稍微不同。

具体可见这篇文章,用一个例子很清楚讲明,在性能优化上尽量选用useEffect,在解决页面渲染更新会闪烁可以用useLayoutEffect。

useRef:获取实例dom或组件方法,必须是类组件

步骤:导入useRef函数,通过ref绑定要获取的元素,执行useRef并传入null,这将会返回一个含有current属性的对象。

import React, { useRef, useEffect } from 'react'
//app组件里绑定
<UseRef1 ref={hook} />
<p ref={pRef}>useRef学习,标签实例</p>

//获取
 const pRef = useRef(null)
 const hook = useRef(null)
  useEffect(() => {
    console.log(pRef.current)
    console.log(hook.current.state.name)
  }, [])

useContext:祖孙组件响应式更新

一个例子直接说明梗概。

import React, { createContext, useContext, useState } from 'react'

//1.创建上下文
const Context = createContext()

//2.在顶层app组件上,使用Providr包裹孙组件,value传值
const [count,setCount]=useState(10)
<Context.Provide value={count}>
      <div>
        <Son />
    	<button onClick={()=>{setCount(count+1)}}></button>
      </div>
</Context.Provider>

//3.在son组件里调用useContext方法,Context和createContext保存的变量一致
const count = useContext(Context)
//这样孙组件就可以显示或同步app组件的值

useReducer

const [ state,dispatch ] = useReducer(reducer, initState, init)

接收三个参数,分别为:处理状态更新的reducer,状态初始值,状态初始化函数。

有两种传递方式:不传第三个参数,如1;state数据比较复杂,可以将第二个参数作为第三个参数传入,如2。

最后,useReducer将返回两个东西,一个当前最新的状态state,一个是更新状态的dispatch。

//1.将状态初始值作为第二个参数传入
const [state, dispatch] = useReducer(
    reducer,
    {count: initState}
)
//2.惰性初始化,将第二个参数作为第三个函数传入
function init(initState){
    return {count: initState}
}

function renducer(state,action){
    switch{
        case "change":
            return {count: state.count - 1}
        case "reset":
            return init(ac)    
        //...
    }
}

function Counter({initState}){
    const [ state,dispatch ] = useReducer(reducer, initState, init)
    return(
    <>
    	<button onClick={() => dispath({type: 'change',count: initState})}></button>    
    </>
    )
}

useCallback

入参和useEffect,接收两个参数(fun,[]),一个处理函数,另一个关联的状态或数组,这个变了就重新执行。

那为啥要用useCallback:那是因为在函数组件里的函数,会随着状态值的更新而重新渲染,函数也会频繁被定义且组件通信很耗性能。使用useCallback+memo可以解决上述问题

useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

useMemo(相当于vue的computed)

入参和useEffect,接收两个参数(fun,[]),一个处理函数,另一个关联的状态或数组,这个变了就重新执行。如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。

官方建议:不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo

useCallback + useMemo

痛点见上述

//使用Memo后确实不会影响了,但父组件传值过来呢
const Son = React.memo(function Son(){
    ...
})

//父组件:这样就不会
const childClick = useCallback(() => {}.[])
<Son click={childClick} />

最后

持续更新中...