React hook的使用

Hook是什么
一组钩子函数的集合
功能:增强了函数组件的功能
状态
生存周期
hook不能提供所有的生命周期的功能
引用
其它功能,可以自定义hook

hook的使用
class组件 功能齐全,但使用麻烦 状态、生存周期、引用
函数组件+hook 功能齐全,而且使用方便 状态、生存周期、引用、其它

1、useState和useEffect的使用

在使用useState() Hook 时,必须遵循 Hook 的规则
仅顶层调用 Hook :不能在循环,条件,嵌套函数等中调用useState()。在多个useState()调用中,渲染之间的调用顺序必须相同。仅从React 函数调用 Hook:必须仅在函数组件或自定义钩子内部调用useState()

useState 只有简单的String,Boolean等可以直接使用 可以是一些比较简单的表达式
处理复杂状态要改用useReducer()

简单数组或对象的修改,可以使用useState

useEffect第二个参数的使用
React Hooks只能用于函数组件,而每一次函数组件被渲染,都是一个全新的开始;
1、每一个全新的开始,所有的局部变量全都重来,全体失忆;
2、每一次全新的开始,只有Hooks函数(比如useEffect)具有上一次渲染的“记忆”;
3、对于上面说的问题,因为count每次渲染都会改变,而且我们想要useEffect总会用上count的值,所以,就要把count放在useEffect的第二个数组参数里面。

规矩就是:如果useEffect第一个函数参数直接或者间接用上某个变量,就请把这个变量放在useEffect的第二个参数里。
useEffect陷进

//setItems 更新 state 不会将旧值“合并” - 它会使用新值覆盖state。 这与this.setState在类中的工作方式不同。
setItems([
    ...items,
    {
    id: items.length,
    value: Math.random() * 100
    }
]);
import React ,{ useEffect ,useState} from "react"

export default function Main(){
    const [count ,setCount] = useState(0)

    useEffect(()=>{
        setTimeout(()=>{
            setCount(x => x+1)
        },1000)
    })
    return (
        <div>
             <div>{count}</div>
        </div>
    )
}

2、useRef的使用
ref
在类组件中,ref的使用可以和vue中一样,不过该写法在react类组件中逐渐废除

类组件

//this.refs.ss.style.color = 'red'  这种写法浏览器控制台会发出警告
export default class Main extends React.Component{
    constructor(props){
        super(props)
    }

    render(){
        return (
            <div>
                 <Button onClick={ () => {
                     this.refs.ss.style.color = 'red'
                 }}>+1</Button>
                 <span ref="ss">sss</span>
            </div>
        )
    }
}

函数组件

import React ,{useRef} from "react"

export default function Main(){
    const ss = useRef()  
    return (
        <div>
            <Button onClick={ () => {
                ss.current.style.color = 'red'
            }}>+1</Button>
            <span ref={ss}>sss</span>
        </div>
    )
}

3、useContext的使用
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。
当前的 context 值由上层组件中距离当前组件最近的 <TextContext.Provider> 的 value prop 决定。
当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,
并使用最新传递给 MyContext provider 的 context value 值。

import React ,{ useContext} from "react"

//TextContext 是自定义的一个常量
const TextContext = React.createContext({})   
const One = ()=>{
    const { name } = useContext(TextContext)

    return (
        <p>one:{name}</p>
    )
}
const Two = ()=>{
    const { name } = useContext(TextContext)

    return (
        <p>two:{name}</p>
    )
}

export default function Main(){
   
    return (
        <div>
            <TextContext.Provider value={{name:'terry'}}>
                <One />
                <Two />
            </TextContext.Provider>
        </div>
    )
}

4、useCallback和useMemo的使用
useCallback和useMemo的参数跟useEffect一致,他们之间最大的区别有是useEffect会用于处理副作用,而前两个hooks不能。
useMemo和useCallback都会在组件第一次渲染的时候执行,之后会在其依赖的变量发生改变时再次执行;并且这两个hooks都返回缓存的值,useMemo返回缓存的变量useCallback返回 缓存的函数

useMemo

import React,{ useState } from "react"
export default function About(){
    const [count, setCount] = useState(1);
    const [val, setValue] = useState('小明');
    function add() {
        console.log('compute');
        let sum = 0;
        for (let i = 0; i < count * 10; i++) {
            sum += i;
        }
        return sum;
    }

    return (
        <div>
           <h4>{count}---{add()}</h4>
            {val}
            <div>
                <button onClick={() => setCount(count + 1)}>+1</button>
                <input value={val} onChange={event => setValue(event.target.value)}/>
            </div>
        </div>
    )
}

运行这个代码,我们会发现,无论我们点击按钮或者在输入框添加值,在后台都会打印出compute,
然而add函数与val并无关系,这就造成了性能的损耗。我们要改成当我们只点击按钮时,add函数才调用。

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

export default function About() {
    const [count, setCount] = useState(1);
    const [val, setValue] = useState('小明');
    //useMemo
    const add = useMemo(() => {
        console.log('compute');
        let sum = 0;
        for (let i = 0; i < count * 10; i++) {
            sum += i;
        }
        return sum;
    },[count])
 
    return (
        <div>
            <h4>{count}-{add}</h4>
            {val}
            <div>
                <button onClick={() => setCount(count + 1)}>+c1</button>
                <input value={val} onChange={event => setValue(event.target.value)}/>
            </div>
        </div>
    );
}

这是我们发现,只有当我们点击了按钮时,add函数才被调用,节省了性能的消耗。

useCallback
1、问题引发
子组件onChange调用了父组件的handleOnChange
父组件handleOnChange内部会执行setText(e.target.value)引起父组件更新
父组件更新会得到新的handleOnChange,传递给子组件,对于子组件来说接收到一个新的props
子组件进行不必要更新

2、使用useCallback解决

import React, { useState, memo, useMemo, useCallback } from 'react'

const Child = memo((props) => {
  console.log(props);

  return (
    <div>
      <input type="text" onChange={props.onChange}/>
    </div>
  )
})

export default function About() {
  const [count, setCount] = useState(0)
  const [text, setText] = useState('')
  
  //useCallback
  const handleOnChange = useCallback((e) => {
    setText(e.target.value)
  },[])

  return (
    <div>
      <div>count: {count}</div>
      <div>text: {text}</div>
      <button onClick={() => {
        setCount(count + 1)
      }}>+1</button>
      <Child onChange={handleOnChange} />
    </div>
  )
}

handleOnChange被缓存了下来,尽管父组件更新了,但是拿到的handleOnChange还是同一个
对比useMemo,useMemo缓存的是一个值,useCallback缓存的是一个函数,是对一个单独的props值进行缓存
memo缓存的是组件本身,是站在全局的角度进行优化

7、useReducer的使用

const [state, dispatch] = useReducer(reducer, initialState);

在 hooks 中提供了的 useReducer 功能,可以增强 ReducerDemo 函数提供类似 Redux 的功能,引入 useReducer 后,
useReducer 接受一个 reducer 函数作为参数,reducer 接受两个参数一个是 state 另一个是 action 。
然后返回一个状态 count 和 dispath,count 是返回状态中的值,而 dispatch 是一个可以发布事件来更新 state 的。

import React,{useReducer} from 'react'

export default function ReducerDemo() {
    const [count, dispath] = useReducer((state,action)=> {
        //...
    }, 0);
    return (
        <div>
            <h1 className="title">{count}</h1>
        </div>
    )
}

在 useReducer 传入 reducer 函数根据 action 来更新 state,如果 action 为 add 正增加 state 也就是增加 count。
在 button 中调用 dispatch 发布 add 事件,发布 add 事件后就会在 reducer 根据其类型对 state 进行对应操作,更新 state。

export default function ReducerDemo() {
    const [count, dispath] = useReducer((state,action)=> {
        if(action === 'add'){
            return state + 1;
        }
        return state;
    }, 0);
    return (
        <div>
            <h1 className="title">{count}</h1>
            <button className="btn is-primary"
                onClick={()=> dispath('add')}
                >Increment</button>
        </div>
    )
}

实例

import React , { useReducer }  from "react"

export default function New(){
    const myReducer = (state ,action) => {
        switch(action.type){
            case('countUp'):
                return {
                    ...state,
                    count: state.count + 1
                }
                default:
                    return state
        }
    }

    const [state , dispatch ] = useReducer(myReducer ,{count : 0})

    return (
        <div className="contentList">
                <button onClick={() => dispatch({ type: 'countUp' })}> +1 </button>
                <p>Count: {state.count}</p>
        </div>
    )
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值