React-Hooks从0到1

1:为什么需要react-Hooks

Hook 时react 16.8的新增特性,它可以让我们在不编写class的情况下使用state以及其他的react特性(比如生命周期)

class组件相对于函数式组件的优势

(1)
√√√ class组件可以定义自己的state,用来保存组件内部的状态。
xxx 函数式组件不可以,因为函数每次调用都会产生新的临时变量。

(2)

√√√ class组件有自己的生命周期,我们可以在对应的生命周期中完成自己的逻辑。比如在componentDIdMount种发送网络请,并且该生命函数只会执行一次。
xxx 函数式组件在学习hooks之前,如果在函数中发送网络请求,意味着每次重新渲染都会发送一次网络请求。

(3)
√√√ class组件在状态改变时只会重新执行render函数,以及我们希望重新调用新的生命周期函数componentDidUpdate等
xxx 函数式组件在重新渲染的时候,整个函数都会被执行,似乎没什么地方可以只让他们被调用一次。

所以:在Hook出现之前,对于上面这些情况我们通常会编写class组件。

class组件存在的问题

  • 我们最初在编写一个class组件的时候,往往逻辑比较简,但是随着业务需求的增加,业务往往会比较多,导致我们的calss组件变得越来越复杂。
  • 对于这样的class实际上非常难以拆分:因为他们的逻辑往往混在一起,强行拆分反而会造成过度设计,增加代码的复杂度。
  • 对于不是很熟悉ES6的开发人员而言,ES6的class式学习React的一个障碍。
  • 组件状态的复用比较难。包括共享状态等。

2:Hook的出现

Hook的出现可以解决上面的问题。

== 简单总结一下Hooks:==

它可以让我们在不编写class的情况下使用state以及其他的React特性
但是我们可以由此延申初许多的写法,来让我们前面提到的问题得到解决.

Hook的横空出现

Hook的使用场景:
Hook的出现基本可以替代我们之前使用class组建的地方(除了一些非常不常用的场景)
Hook只能在函数组件中使用,不能再类组件或者函数式组件之外的地方使用它。

3.Hook的初体验

接下来,我们将通过一个计数器案例来对比一下,class组件和Function组件的区别。以及了解一下hook是怎么使用的。

使用class组件来实现一个计数器

import React, {
    
    PureComponent} from 'react'

export default class CounterClass extends PureComponent {
    
    
    
    constructor(props){
    
    
        super(props)


        this.state = {
    
    
            counter:0
        }
    }

    render() {
    
    
        return (
            <div>
                <h2>当前计数:{
    
    this.state.counter}</h2>
                <button onClick={
    
    e => this.increment()}>+1</button>
                <button onClick={
    
    e => this.decrement()}>-1</button>
            </div>
        )
    }

    increment(){
    
    
        this.setState({
    
    
            counter:this.state.counter + 1
        })
    }

    decrement(){
    
    
        this.setState({
    
    
            counter:this.state.counter - 1
        })
    }

}

使用HOOK(结合function)来实现一个计数器

import React, {
    
    useState} from 'react'

export default function CounterHook2() {
    
    
    
    const [count, setCount] = useState(0);
    
    return (
        <div>
            <h2>当前计数: {
    
    count}</h2>
            <button onClick={
    
    e => setCount(count + 1)}>+1</button>
            <button onClick={
    
    e => setCount(count - 1)}>-1</button>
        </div>
    )
}

hook中处理状态的部分:
/**
* Hook : useState 使用状态
* > 本身是一个函数,函数来自我们的react这个包
* > 参数和返回值
* 1.参数:作用是给创建出来的状态一个默认值
* 2.返回值:
* 元素1:当前state的值
* 元素2:设置新的值的时候返回的一个函数
*/

在这里插入图片描述

Hook就是javascript函数,这个函数可以帮助你钩入(hook into)react state以及生命周期等特性。

但是他在使用的时候会有两个额外的规则:
1 只能再函数最外层带哦用hook,不要再循环没条件判断,或者子函数中调用。
2 只能再React的函数组件中调用hook。不要再其他javascript函数中调用。
在这里插入图片描述

使用HOOK 当一个组件内部存在多个变量的时候的处理方式

处理复杂的数据:

import React, {
    
    useState} from 'react'

export default function ComplexHookState() {
    
    
    
const [friends, setFriends] = useState(['js','java'])

    return (
        <div>
            <h2>好友列表</h2>

            <ul>
                {
    
    
                    friends.map( (item,index) => {
    
    
                        return (
                            <li key={
    
    index}>{
    
    item}</li>
                        )
                    })
                }
            </ul>


            <button onClick={
    
    e => setFriends([...friends,"康家豪"])}>添加朋友</button>
        </div>
    )
}

处理复杂的数据:

import React, {
    
     useState } from 'react'

export default function ComplexHookState() {
    
    

    const [friends, setFriends] = useState(['js', 'java'])
    const [students, setStudents] = useState([
        {
    
     id: 110, name: 'why', age: 19 },
        {
    
     id: 112, name: 'kobe', age: 30 },
        {
    
     id: 120, name: 'lilei', age: 78 }
    ])

    function studentsAgeIncrement(index) {
    
    
        const newStudents = [...students];
        newStudents[index].age += 1;
        setStudents(newStudents)
    }


    return (
        <div>
            <h2>好友列表</h2>

            <ul>
                {
    
    
                    friends.map((item, index) => {
    
    
                        return (
                            <li key={
    
    index}>{
    
    item}</li>
                        )
                    })
                }

            </ul>
            <button onClick={
    
    e => setFriends([...friends, "康家豪"])}>添加朋友</button>
            <hr />

            <h2>学生列表</h2>
            <ul>
                {
    
    
                    students.map((item, index) => {
    
    
                        return (
                            <li key={
    
    item.id}>
                                id:{
    
    item.id} name:{
    
    item.name} age:{
    
    item.age}
                                <button onClick={
    
    e => studentsAgeIncrement(index)}>age+1</button>
                            </li>
                        )
                    })
                }
            </ul>



        </div>
    )
}

在这里插入图片描述

4.认识 Effect Hook

目前我们已经通过hook在函数式组件中定义state,那么类似于生命周期这些怎么实现呢/
Effect Hook 可以帮助你来完成一些类似于class中声明周期的功能.

现在我们有一个需求:页面的title显示当前的数字

使用class组件来实现:

import React, {
    
     PureComponent } from 'react'

export default class ClassCounterTitleChange extends PureComponent {
    
    
    
    constructor(props){
    
    
        super(props)

        this.state = {
    
    
            counter:0
        }
    }
    
    //类组件使用生命周期来实现 title 根据counter来发生改变
    componentDidMount() {
    
    
        document.title = this.state.counter;
    }

    componentDidUpdate() {
    
    
        document.title = this.state.counter;
    }

    render() {
    
    
        return (
            <div>
                <h2>当前计数:{
    
    this.state.counter}</h2>
                <button onClick={
    
    e => this.increment()}>add one</button>
            </div>
        )
    }

    increment(){
    
    
        this.setState({
    
    
            counter:this.state.counter + 1
        })
    }
}

使用Hook(结合useEffect)实现

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

export default function HookCounterTitleChange() {
    
    
    
    const [state, setstate] = useState(0)

    /**
     * useEffect的使用
     * 可以用来模拟生命周期
     */
    useEffect(() => {
    
    
        document.title = state;
    })

    return (
        <div>
            <h2>当前计数:{
    
    state}</h2>
            <button onClick={
    
     e => setstate(state + 1)}>+1</button>
        </div>
    )
}

useEffect模拟订阅和取消订阅

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

export default function EffectHookCancleDemo() {
    
    

    const [count, setCount] = useState(0)

    useEffect(() => {
    
    
        console.log("发生了事件订阅")



        return () => {
    
    
            console.log("取消了订阅事件")
        }
    },[])

    return (
        <div>
            <h2>03_eFfect模拟订阅和取消订阅</h2>
            <h2>当前计数:{
    
    count}</h2>

            <button onClick={
    
    e => setCount(count + 1)}>+1</button>`
        </div>
    )
}

useEffect详解

useEffect ( () => {
console.log('修改DOM‘)
} )

useEffect 参数1: 传入一个箭头函数,页面刷新调用这个函数
useEffect 参数2: 传入一个数组,数组里传入依赖,当依赖中某个变量发生改变的时候就会再次调用useEffect函数执行。

useContext详解

useContext可以实现数据的共享:
举个例子:

先定义两个组件:
export const UserContext = createContext()
export const ThemeContext = createContext()



然后下方嵌套使用:
<UserContext.Provider value={
    
    {
    
     name: '康家豪', age: 18 }}>
                <ThemeContext.Provider>
                    <UseContextDemo value={
    
    {
    
     weather: "多云", home: '宝鸡' }} />
                </ThemeContext.Provider>
            </UserContext.Provider>


子组件中获取数据:
import React from 'react'
import {
    
     useContext,useState } from 'react'

import {
    
     UserContext, ThemeContext } from '../App'

export default function UseContextDemo(props) {
    
    

    const user = useContext(UserContext);
    const theme = useContext(ThemeContext)

    console.log(user,theme,props)

    return (
        <div>
            <h2>useContextDemo</h2>
             
        </div>
    )
}

5.补充的一些Hooks

useReducer:useState数据逻辑复杂时的替代方案,可以在UseReducer中拆分逻辑

在这里插入图片描述

UseCallBack实际的目的是为了进行性能的优化

useCallBack 会返回一个函数的memoized(记忆的)值’
在依赖不变的情况下,多次定义的时候,返回的值是相同的。

举个例子:

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

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

    const increment = () => {
    
    
        console.log('执行increment1函数');
        setCount(count + 1)
    }



    
    //使用useCallBack进行性能优化

    //没有任何依赖的时候,count永远都是从0开始计算的
    const increment2 = useCallback(() => {
    
    
        console.log('执行increment2函数');
        setCount(count + 8)
    },[])

    return (
        <div>
            当前计数:{
    
    count}
            <button onClick={
    
    increment}>按钮1</button>
            <button onClick={
    
    increment2}>按钮2</button>
        </div>

    )
}

在这里插入图片描述

UseMemo实际的目的是为了进行性能的优化

useMemo 会返回一个函数的memoized(记忆的)值’
在依赖不变的情况下,多次定义的时候,返回的值是相同的。

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

export default function UseMemo1() {
    
    
    
    const [count, setCount] = useState(10)
    const [show, setShow] = useState(true)
        let total = 0;
        for(var i = 0; i < count; i++){
    
    
            total += i;
        }

    return (
        <div>
            <h2>计算数字的和:{
    
    total}</h2> 
            <button onClick={
    
    e => setCount(count + 1)}>+1</button> 
            <button onClick={
    
    e => setShow(!show)}>show切换</button>       
        </div>
    )
}

当我们执行show切换的时候,这个时候上面的累加函数就会重新执行一次,影响网站的性能。

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

function calcCount(count){
    
    
    console.log('calcCount重新计算')
    let total = 0;
    for(var i = 0; i < count; i++){
    
    
        total += i;
    }
    return total;
}


export default function UseMemo1() {
    
    
    
    const [count, setCount] = useState(10)
    const [show, setShow] = useState(true)
       
    // const total = calcCount(count);

    //使用useMemo来优化函数
    const total = useMemo(() => {
    
    
        return calcCount(count)
    },[count])

    //传入依赖count 表明当count发生改变的时候,这里的代码才会重新执行一次



    return (
        <div>
            <h2>计算数字的和:{
    
    total}</h2> 
            <button onClick={
    
    e => setCount(count + 1)}>+1</button> 
            <button onClick={
    
    e => setShow(!show)}>show切换</button>       
        </div>
    )
}

UseRef

用法1:引入DOM(或者组件,但是需要是class组件)元素
用法2:保存一个数据,让这个对象在整个生命周期中可以保存不变。

用法一代码示例:

import React ,{
    
    useRef}from 'react'

class TestCpn extends React.Component {
    
    
    render(){
    
    
        return <h2>天气很好</h2>
    }
}


export default function RefHookDemo01() {
    
    
    
    const titleRef = useRef()
    const cpn1 = useRef()
    
    function changeDOM(){
    
    
        titleRef.current.innerHTML = "HELLO WORLD"
        console.log(cpn1.current)
    }

    
    return (
        <div>
            <h2 ref={
    
    titleRef}>RefHookDemo01</h2>


            <button onClick={
    
     e => changeDOM() }>修改DOM</button>

            <TestCpn ref={
    
    cpn1}/>
        </div>
    )
}

这样可以使用useRef来调用DOM元素和class 组件(函数式组件不可以使用useRef)

用法二代码示例:

import React,{
    
    useRef, useState, useEffect} from 'react'

export default function RefHookDemo02() {
    
    

    const [count, setCount] = useState(0)

    // console.log(count)
    //这里增加count的时候,count的确增加了

    const numRef = useRef(count);
    //使用useRef会保留最原本的值

    useEffect(() => {
    
    
        numRef.current = count;
    }, [count])

    return (
        <div>
            <h2>RefHookDemo02</h2>
            <h2>上一次count的值:{
    
    numRef.current}</h2>
            <h2>当前的count的值:{
    
    count}</h2>
            <button onClick={
    
    e => setCount(count + 1)}>+1</button>
        </div>
    )
}

可以通过useRef实现一个不会更改的数据。
可以通过useRef 配合 useEffect来实现保存上一次数据状态。

UseImperativeHandle

觉得有一丝毛用就没整理了。

UseLayoutEffect

在这里插入图片描述

4.自定义Hook

认识自定义hook

import React,{
    
    useEffect} from 'react'


function Home(){
    
    
    useLoginAndCancle('home')
    return <h2>Home</h2>
}

function About(){
    
    
    useLoginAndCancle('about')
    return <h2>About</h2>
}


export default function CustomLifeHookDemo01() {
    
    

    useLoginAndCancle('customLifeHookDemo')
    return (
        <div>
           CustomLifeHookDemo01 
           <Home/>
           <About/>
        </div>
    )
}


function useLoginAndCancle(name){
    
    
    useEffect(() => {
    
    
        
        console.log(`${
      
      name}被创建出来了`)

        return () => {
    
    
            console.log(`${
      
      name}组件被销毁了`)
        }
    }, [])
}

自定义获取页面scroolY的hook

import React from 'react'
import {
    
     useEffect } from 'react'

export default function HookScrool() {
    
    

    useEffect(() => {
    
    
        const handleScroll = () => {
    
    
            console.log(window.scrollY)
        }

        document.addEventListener('scroll',handleScroll)

        return () => {
    
    
            document.removeEventListener('scroll',handleScroll)
        }
    })

    return (
        <div style={
    
    {
    
    padding:"1000px 0"}}>
            <h2>
                HookScrool
            </h2>
        </div>
    )
}

当然最后我们在项目开发中,可以将hook封装为一个文件夹,将我们对应写好的自定义hook封装好并且导出,这样我们就可以在爱多个组件内部使用我们封装好的自定义hook。

————————————————————————————————————————--------

react hooks 补充

react hooks 配合 redux进行使用

import React, {
    
     memo, useEffect } from 'react';

import {
    
     connect, useDispatch, useSelector } from 'react-redux';

import {
    
     getTopBannerAction } from './store/actionCreators'

function KJHRecommend(props) {
    
    
    
    // 组件和redux关联: 获取数据和进行操作
    const dispatch = useDispatch();

    // 发送网络请求
    useEffect(() => {
    
    
        dispatch(getTopBannerAction());
    }, [dispatch])

    //拿到数据
    const {
    
    topBanners} = useSelector(state => ({
    
    
        topBanners: state.recommend.topBanners
    }))
    return (
        <div>
            <h2>KJHRecommend : {
    
    topBanners.length}</h2>
        </div>
    )
}

export default memo(KJHRecommend);

useDispatch的使用

const dispatch = useDispatch()

主要作用:
返回Redux store中对dispatch函数的引用。你可以根据需要使用它。

useSelect的使用

const result : any = useSelector(selector : Function, equalityFn? : Function)

主要作用:
从redux的store对象中提取数据(state)。

总有一天我会忘了你,但是我永远欣赏你,我的姑娘。

猜你喜欢

转载自blog.csdn.net/qq_43955202/article/details/108611015