zoukankan      html  css  js  c++  java
  • React Hooks 一步到位

    useState

    用来声明状态变量。

    import React, { useState } from 'react';
    // ...
    const [ count , setCount ] = useState(0);
    // ...
    
    • count 声明的变量
    • setCount 设用来更新变量的函数
    • 0 初始值
    • 多个状态声明不能出现在条件判断语句中

    useEffect

    用来代替生命周期函数。

    import React, { useEffect } from 'react';
    
    useEffect(()=>{
        // some code
    })
    
    • 第一次组件渲染和每次组件更新都会执行这个函数
    • useEffect中的函数的执行不会阻碍浏览器更新视图,这些函数是异步的

    使用 useEffect 实现类似 componentWillUnmount

    useEffect(()=>{
        return () => { 
            // some code
        }
    })
    
    • 返回一个函数实现解绑
    • 但是这样会导致每次状态发生变化,useEffect 都进行解绑
    useEffect(()=>{
        return () => { 
            // some code
        }
    }, [])
    

    使用第二个参数,制定哪些状态发生变化时再解绑

    useContext

    跨越组件层级直接传递变量,实现状态共享。

    • useContext 解决的是组件之间值传递的问题
    • redux 解决的是应用中统一管理状态的问题
    • useContext 通过和 useReducer 的配合使用,可以实现类似 Redux 的作用

    Outer 组件

    import React, { createContext } from 'react'
    const ValueContext = createContext()
    function Outer(){
        return (
            <>
                <ValueContext.Provider value={'我是传向 Inner 组件的值'}>
                    <Inner />
                </ValueContext.Provider>
            </>
        )
    }
    export default Outer;
    
    • 使用 createContext 创建 context
    • 使用 createContext 同时生成组件
    • 闭合标签将组件包裹

    Inner 组件

    import React, { useContext  } from 'react'
    const value = useContext(CountContext)
    function Inner(){
        return (
            <>
                <p>{value}</p>
            </>
        )
    }
    export default Inner;
    

    使用 useContext 来使用上下文

    useReducer

    用来实现类似 redux 功能

    import React, { useReducer } from 'react';
    
    function Demo(){
        const [ count, dispatch ] = useReducer((state,action)=>{
            switch(action){
                case 'add':
                    return state+1
                case 'sub':
                    return state-1
                default:
                    return state
            }
        },0)
        return (
           <>
               <h2>分数:{count}</h2>
               <button onClick={()=>dispatch('add')}>加</button>
               <button onClick={()=>dispatch('sub')}>减</button>
           </>
        )
    }
    
    export default Demo
    
    • state 第一个参数 状态
    • action 控制业务逻辑的判断参数

    模拟 Redux

    • useContext:可访问全局状态,避免一层层的传递状态
    • useReducer:通过action的传递,更新复杂逻辑的状态

    颜色共享组件 color.js

    import React, { createContext,useReducer } from 'react';
    
    export const ColorContext = createContext({})
    export const UPDATE_COLOR = 'UPDATE_COLOR'
    
    const reducer = (state, action) => {
        switch(action.type){
            case UPDATE_COLOR:
                return action.color
            default:
                return state
        }
    }
    
    export const Color = props => {
        const [color, dispatch] = useReducer(reducer, 'blue')
        return (
            <ColorContext.Provider value = {{color,dispatch}}>
                {props.children}
            </ColorContext.Provider>
        )
    }
    
    • 用 {props.children} 来显示子组件
    • 将 color 和 dispatch 共享出去

    showArea.js

    import React , { useContext } from 'react';
    import { ColorContext } from './color';
    
    function ShowArea(){
        const { color } = useContext(ColorContext)
        return (<div style={{ color:color }}>字体颜色为{ color }</div>)
    }
    
    export default ShowArea
    
    • 注意 引入 ColorContext 使用了大括号

    Buttons.js

    import React , { useContext } from 'react';
    import { ColorContext, UPDATE_COLOR } from './color'
    
    function Buttons(){
        const { dispatch } = useContext(ColorContext)
        return (
            <div>
                <button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"red"})}}>红色</button>
                <button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"yellow"})}}>黄色</button>
            </div>
        )
    }
    
    export default Buttons
    

    Demo.js

    import React, { useReducer } from 'react';
    import ShowArea from './ShowArea';
    import Buttons from './Buttons';
    import { Color } from './color';   //引入Color组件
    
    function Demo(){
        return (
            <>
                <Color>
                    <ShowArea />
                    <Buttons />
                </Color>
            </>
        )
    }
    
    export default Demo
    

    useMemo

    用来解决使用 React hooks 产生的无用渲染的性能问题。

    import React , {useState,useMemo} from 'react';
    
    function Demo(){
        const [xiaohong , setXiaohong] = useState('小红待客状态')
        const [zhiling , setZhiling] = useState('志玲待客状态')
        return (
            <>
                <button onClick={()=>{setXiaohong(new Date().getTime())}}>小红</button>
                <button onClick={()=>{setZhiling(new Date().getTime()+',志玲向我们走来了')}}>志玲</button>
                <ChildComponent name={xiaohong}>{zhiling}</ChildComponent>
            </>
        )
    }
    
    function ChildComponent({name,children}){
        function changeXiaohong(name){
            console.log('她来了,她来了。小红向我们走来了')
            return name+',小红向我们走来了'
        }
    
        const actionXiaohong = changeXiaohong(name)
        return (
            <>
                <div>{actionXiaohong}</div>
                <div>{children}</div>
            </>
        )
    }
    
    export default Demo
    

    点击志玲按钮,小红对应的方法执行,虽然结果没变,但是每次都执行,损耗性能。

    function ChildComponent({name,children}){
        function changeXiaohong(name){
            console.log('她来了,她来了。小红向我们走来了')
            return name+',小红向我们走来了'
        }
    
        const actionXiaohong = useMemo(()=>changeXiaohong(name),[name]) 
        return (
            <>
                <div>{actionXiaohong}</div>
                <div>{children}</div>
            </>
        )
    }
    

    第二个参数 [name] 匹配成功,才会执行。

    useRef

    • 用来获取React JSX中的DOM元素
    • 用来保存变量
    import React, { useRef} from 'react';
    function Demo(){
        const inputEl = useRef(null)
            inputEl.current.value = "给 input value属性 赋值"
        return (
            <>
                <input ref={inputEl} type="text"/>
            </>
        )
    }
    
    export default Demo
    
    import React, { useRef, useState, useEffect } from 'react'
    
    function Demo(){
        const inputEl = useRef(null)
            inputEl.current.value="给 input value属性 赋值"
    
        const [text, setText] = useState('默认值')
        const textRef = useRef()
    
        useEffect(()=>{
            textRef.current = text
        })
    
        return (
            <>
                <input ref={inputEl} type="text"/>
                <input value={text} onChange={(e)=>{setText(e.target.value)}} />
            </>
        )
    }
    
    export default Demo
    
    • text 每次发生变化,将值保存到 useRef 中
    • 使用 useEffect 实现每次状态变化都进行变量重新赋值
    • 很少用到这个功能(保存变量)

    自定义 Hooks

    编写自定义函数实现获取浏览器窗口

    import React, { useState, useEffect, useCallback } from 'react';
    
    function useWinSize(){
        const [ size , setSize] = useState({
            document.documentElement.clientWidth,
            height:document.documentElement.clientHeight
        })
    
        const onResize = useCallback(()=>{
            setSize({
                 document.documentElement.clientWidth,
                height: document.documentElement.clientHeight
            })
        },[])
    
        useEffect(()=>{
            window.addEventListener('resize',onResize)
            return ()=>{
                window.removeEventListener('resize',onResize)
            }
        },[])
    
        return size;
    }
    
    function Demo(){
        const size = useWinSize()
        return (
            <div>页面Size:{size.width} x {size.height}</div>
        )
    }
    
    export default Demo 
    
    • 命名要使用 use 开头以确认该函数是自定义 Hook 而不是组件
    • useCallback 用来缓存方法 ( useMemo 是为了缓存变量)
    • 第一次进入方法时用 useEffect 来注册 resize 监听事件
    • 防止一直监听所以在方法移除时,使用return的方式移除监听
    • 最后在 Demo 组件中使用

    文章参考

    • 官方文档
    • 哔哩哔哩up主技术胖的 视频
  • 相关阅读:
    BZOJ 3132: 上帝造题的七分钟 树状数组+差分
    PAT Advanced 1006 Sign In and Sign Out (25 分)
    PAT Advanced 1011 World Cup Betting (20 分)
    PAT Basic 1032 挖掘机技术哪家强 (20 分)
    PAT Basic 1028 人口普查 (20 分)
    PAT Basic 1004 成绩排名 (20 分)
    大数据数据库HBase(二)——搭建与JavaAPI
    PAT Advanced 1009 Product of Polynomials (25 分)(vector删除元素用的是erase)
    PAT Advanced 1002 A+B for Polynomials (25 分)(隐藏条件,多项式的系数不能为0)
    PAT Basic 1041 考试座位号 (15 分)
  • 原文地址:https://www.cnblogs.com/guangzan/p/12210806.html
Copyright © 2011-2022 走看看