React Hooks提供了新特性来给纯函数组件可以管理状态

学过react都知道纯函数组件没有生命周期钩子,而且还不能更新状态,只有class组件有生命周期钩子和状态

而一个好的组件要有高独立性,高可复用性,而class组件本身就是有状态,因此要复用起来比较麻烦,而且还有个this缺陷

React Hooks的出现,是因为类组件会继承React.Component父类,而React.Component父类拥有大量的方法和属性,在开发一些小型组件时,完全没有必要用到这么多的方法和属性,就好吧杀鸡用屠龙刀一样,可以但是没有必要,而纯函数组件就不存在这些方法和属性,可谓是轻量级

例如:

class组件:

class Hi extends React.Component{
    constructor(props) {
        super(props)
        this.state = { count:0 }
    }
    render(){
        console.log(this.state.count)
        return(
            <div>
                <p>数据:{this.state.count}</p>
                 <button onClick={this.addGo.bind(this)}>GO</button>
            </div>
        )
    }
    addGo(){
        this.setState({count:this.state.count+1})
    }
}

那么函数组件+React Hooks怎么实现状态更新呢?

而function组件想更新状态可以通过React Hooks来实现,例如:

例如:

import React, { useState } from 'react'
function Hi(){
    const [ count , setCount ] = useState(0)
    return (
        <div>
            <p> 数据:{count} </p>
            <button onClick={()=>{setCount(count+1)}}>GO</button>
        </div>
    )
}

没错就是这么简单,看起来函数组件+React Hooks更简洁,更容易理解

useState是一个hook函数,是react原生自带的

useState提供了声明状态,读取状态,修改状态的方法

const [ count , setCount ] = useState(0)

意思就是声明状态变量为count,count状态的初始值设置为0

<button onClick={()=>{setCount(count+1)}}>GO

而这个就是改变状态,调用setCount()函数来实现,该函数接受的参数是已经修改过的新状态,react就会进行重新渲染组件

但是有一个坏处就是,如果存在多个状态,又没有key表示,如何知道状态是对于哪个useState呢?

实质上是通过useState出现顺序来确定,如果对应的顺序不对就会报错,因此React Hooks不能出现于条件判断或者定时器之类会影响顺序的语句中


状态有,生命周期也有

例如:

import React, { useState , useEffect } from 'react'
function Hi(){
    const [ count , setCount ] = useState(0)
    useEffect(()=>{
        console.log("data:"+count)
    })
    return (
        <div>
            <p> 数据:{count} </p>
            <button onClick={()=>{setCount(count+1)}}>GO</button>
        </div>
    )
}
export default Hi;

可以看到在第一次渲染和更新渲染都会执行一次,而在这里useEffect()的参数是一个匿名指针函数,函数里面是打印输出一句话,从这句话可以看出在第一次渲染的时候和更新的时候都会触发

useEffect()相当于componentDidMonut和componentDidUpdate

而且useEffect()中定义的函数是异步执行的,而componentDidMonut和componentDidUpdate是同步执行,各有优点缺点


实现类似componentWillUnmount生命周期钩子(组件销毁之前执行)的功能

注意:useEffect会出现副作用,当每次的状态发生变化时候,useEffect都会进行解除绑定

通过useEffect第二个参数,该参数是一个数组,该数组可以存放大量于状态相对应的变量,也可以了解为监控状态,而当传入空数组[]的时候,那么就是当组件被销毁才进行解除绑定,也就是说实现了componentWillUnmount的功能

function Data() {
    useEffect(()=>{
        console.log('hallo')
        return ()=>{
            console.log('goodbye')
        }
    },[])
    return (<div>data</dv>);
}

父子组件传值useContext

使用类组件的时候,父子组件之间传值是通过props进行的,但是函数组件并没有constructor构造函数,也因此没有props

通过createContext函数创建useContext

import React, { useState , createContext, useContext } from 'react'
const CountContext = createContext()
...
const [ count , setCount ] = useState(0);
...
<CountContext.Provider value={count}>
</CountContext.Provider>

导入createContext函数,得到一个组件,并且通过该组件来传递或者使用状态

接收状态

const count = useContext(CountContext) return ({count})


Redux有3大核心概念:Action和Reducer和Store

这个Redcuer是一个纯函数,这个函数可以接收两个参数,一个是状态,另一个是控制状态的判断参数,例如:

function demoReducer(state, action) {
    switch(action.type) {
        case 'a':
            return state + 1
        case 'b':
            return state - 1
        default: 
            return state
    }
}

useReducer是用于增强Redcuer来实现类似redux的功能,例如:

import React, { useReducer } from 'react'
function demoReducer(){
    const [ count , dispatch ] =useReducer((state,action)=>{
        switch(action){
            case 'a':
                return state+1
            case 'b':
                return state-1
            default:
                return state
        }
    },0)
    return (
       <div>
           <h2>{count}</h2>
           <button onClick={()=>dispatch('a')}>加</button>
           <button onClick={()=>dispatch('b')}>减</button>
       </div>
    )
}
export default demoReducer

useMemo优化hooks性能

useMemo用于解决无用渲染,函数组件不具备shouldCompnentUpdate生命周期钩子,因此不能通过该组件来决定组件是否更新,每一次调用函数组件都会执行组件内部的全部逻辑

import React , {useState,useMemo} from 'react'
...
const [name, setName] = useState('root')
const data = useMemo(()=>{
    return {
        name
    }
},[name])

useMemo第一个参数是()=>value,第二个参数是监听指定的值是否发生改变

上面会根据name来判断一下,如果name值没有发生改变,那么就不会进行render,而是重复用之前的value,只要发生改变才会重新计算value

useRef可以获取jsx的dom元素,可以用于控制dom,也可以用来存储变量

获取dom元素

import React, { useRef } from 'react'
function Demo(){
    const inputData = useRef(null)
    const onDataClick=()=>{ 
        inputData.current.value="hallo,word"
        console.log(inputData) 
    }
    return (
        <div>
            <input ref={inputData} type="text"/>
            <button onClick = {onDataClick}>显示</button>
        </div>
    )
}
export default Demo

useRef存储变量

    const [text, setText] = useState('goodbye')
    const textRef = useRef()
    useEffect(()=>{
        textRef.current = text;
        console.log(textRef.current)
    })
    ...
    <input value={text} onChange={(e)=>{setText(e.target.value)}} />

每次状态发生改变,都会在同时保存到useRef中


自定义Hooks函数