• React Hooks


    Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性
    React hooks

    基础的 Hook
    • useState
    • useEffect
    • useContext
    额外的 Hook
    • useRef
    • useCallback
    • useMemo
    • useReducer

    接下来我们通过代码一一介绍下这些 hooks

    1. useState 为函数组件引入状态
    // 使用数组解构来命名状态变量,例如 [something, setSomething]
    const [state, setState] = useState(initialState)
    
    • 1
    • 2
    • 纯函数组件没有状态,useState()用于为函数组件引入状态
    • useState的作用:只要组件的state或者props发生改变,组件就会重新渲染
    • useState只能写组件的顶层或者方法中,不能写在条件语句或循环语句中
    • useState的作用就是:申明局部变量和状态,声明变量
    • 修改变量通过 setState来修改
    import React, { useState } from 'react'
    export default function HelloWorld(): any {
      const a = 3, b = 7
      const array = ['Apple', 'banan', 'Peach']
      const [msg, setMsg] = useState<string>('hello world')
      const [count, setCount] = useState<number>(1)
      const [list, setList] = useState<string[]>([])
      const [arrList, setArrList] = useState<string[]>(array)
      
      const addContent = (e: any) => {
        const val = e.target.value
        if (e.keyCode === 13 && val) {
          setList((pre) => [...list, val]) // 将输入的每一项通过展开运算符 push到列表中
          e.target.value = ''
        }
      }
      // const changeMsg = (): any => {
      //   setMsg('Hello!')
      // }
      const add = (): void => {
        if (count < 5) {
          setCount(() =>  count + 1 )
        }
      }
      return (
        <>
          <h2>count的值为:{ count }</h2>
          <h3>{a > b ? '大于' : '小于'}</h3>
          <button onClick={ add }>+</button>
          <input type="text"
            onKeyUp={ addContent }
            placeholder="请输入内容" />
          {/*  */}
          <button onClick={() => (setMsg('hello1'))}>改变文本</button>
          <ul>
            {
              list.map((item) => (<li key={Math.random()}>{ item}</li>))
            }
          </ul>
          <div>
            {
              arrList.map((item, index) => (<div key={index}>{item}</div>))
            }
          </div>
        </>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    2. useEffect 副作用
    • useEffect(setup, dependencies?)
    • setup:处理 Effect 的函数。setup 函数选择性返回一个 清理(cleanup) 函数
    • 可选 dependencies:依赖项
    • 操作DOM,发送请求都属于副作用
    • useEffect有点类似于vue中的watch,可以监听某个变量的变化
    • useEffect 是一个 Hook,因此只能在 组件的顶层 或自己的 Hook 中调用它,而不能在循环或者条件内部调用。如果需要,抽离出一个新组件并将 state 移入其中
    • 如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合
    import React,{ useState, useEffect } from 'react'
    export default function UseEffect() {
        // useEffect接收2个参数,1.是回调函数,2是回调函数依赖的数组 
        // 当数组中的数据发生改变的时候,回调函数会执行
        // useEffect中的第二个参数不存在的时候,那么每次组件渲染的时候,回调函数都会执行
        // useEffect可以用来代替生命周期函数,套路就是"第二个参数的变化"
        const [count, setC] = useState<number>(1)      
        const [count2, setC2] = useState<number>(1) 
        // 第二个参数不存在,所以每次都会执行回调函数 
        useEffect(() => { 
            console.log('每次都会执行, 等价于componentDidMount + componentDidUpdate')
            })
        // 第二个参数如果是空数组,那么只在初始化的时候回调函数执行一次 
        useEffect(() => {
            console.log('只有第一次执行, 等价于componentDidMount')
        }, [])
        
        // 第二个参数有值,且当值发生改变的时候执行回调函数
        useEffect(() =>{
            console.log('当count变化的时候执行,等价于componentDidMount + componentWillUnmount')
            }, [count])
    
      return (
          <>
            <h2>我是UseEffect组件 count值为:{count}</h2>
            <button onClick={()=> setC(count + 1)}>+</button>
            <h2>我是组件2 count值为:{count2}</h2>
            <button onClick={() => setC(count2 + 1)}>+</button>  
        </>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    传递一个函数
    要实际 存储 一个函数,你必须在两种情况下在它们之前加上 () =>
    然后 React 将存储你传递的函数。

    const [fn, setFn] = useState(() => someFunction);
    function handleClick() {
      setFn(() => someOtherFunction);
    }
    
    • 1
    • 2
    • 3
    • 4
    3.useContext 用来解决跨组件传递数据的问题
    • 向组件树深层传递数据
    • 通过 context 更新传递的数据
    • 覆盖组件树一部分的 context
    • 在传递对象和函数时优化重新渲染
    const value = useContext(MyContext)
    
    • 1

    这里还得再提到一个React的API createContext

    使用 createContext 创建组件能够提供与读取的 上下文(context)。

    • createContext(defaultValue)
    • SomeContext.Provider
    • SomeContext.Consumer (老方法)

    用法 createContext(defaultValue)

    • 创建上下文
    • 从一个文件导入和导出上下文
    // 在任意组件外调用 createContext 创建一个上下文
    import { createContext } from 'react';
    
    const ThemeContext = createContext('light');
    
    • 1
    • 2
    • 3
    • 4

    从一个文件导入和导出上下文
    通常,来自不同文件的组件都会需要读取同一个上下文。因此,在一个单独的文件内定义上下文便成了常见做法。以使用 export 语句 将其导出,以便其他文件读取使用:

    // Contexts.js
    import { createContext } from 'react';
    
    export const ThemeContext = createContext('light');
    export const AuthContext = createContext(null);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在其他文件中定义的组件可以使用 import 语句读取或提供该 context

    // Button.js
    import { ThemeContext } from './Contexts.js';
    
    function Button() {
      const theme = useContext(ThemeContext);
      // ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    具体使用

    // 在 src目录下新建一个公共的 useContext 上下文环境
    import React, { createContext, useState } from 'react'
    export const myContext = createContext<any>(null)
    
    • 1
    • 2
    • 3

    在需要嵌套的顶层组件中引入此 useContext

    import React, { useState, useContext } from 'react'
    import { myContext } from './MyContext';
    import Parent from './Parent';
    
    export default function RootComponent() {
        const [count, setCount] = useState<number>(0)
        const [msg, setMsg] = useState<string>('To chaild')
        const increase = () => {
            setCount(() => count + 1)
        }
      return (
          <div>
              <h2>Root 组件</h2>
              <button onClick={increase}>点击</button>
    		{/* 用 myContext.Provider包裹顶层组件,并在 value 属性中传递需要传递的方法或属性 */}
              <myContext.Provider value={{msg, count, increase}}>
                  <Parent />
              </myContext.Provider>
        </div>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在 Parent.tsx 中,通过 useContext使用顶层组件中的属性或方法

    import React, { useContext } from 'react'
    import {myContext} from './myContext';
    import Child from './Child'
    
    export default function Parent() {
    	// 在这里使用存储在 myContext中的数据
        const context = useContext(myContext)
        const login = () => {
            console.log('login is on')
        }
      return (
          <div>
              <h2>Parent</h2>
              <h1 style={{color: 'red'; margin: '20px 0';}}>{msg}</h1>
              <button onClick={login}>Login</button>
              <Child />
          </div>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在 Child.tsx中,通过 useContext将顶层组件中的数据传递给Child

    import React, { useContext } from 'react'
    import { myContext } from './myContext';
    
    export default function Child() {
        const context = useContext<any>(myContext)
        const {count, msg, setCount, increase} = context
      return (
          <div>
              <h2>Child</h2>
              <h1 style={{color: 'blue', marginTop: '0.5rem'}}>{msg} {count} { msg }</h1>
              {/*子组件触发父组件传递过来的方法即可与父组件通信 */}
              <button onClick={increase}>Increase</button>
          </div>
      )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    C#开发的OpenRA游戏之游戏设计思路
    设备巡检管理系统的作用
    马斯克领导的 Twitter 会变成 Web3 平台吗?
    2023年CSP-S赛后总结(2023CSP-S题解)
    定制化精准推送与用户分组策略:数智营销的硬技能
    接口性能测试方案
    [Python]Django 模型
    whois域名查询工具在线使用
    StringTable/StringPool
    小程序路由传参的方法
  • 原文地址:https://blog.csdn.net/qyl_0316/article/details/127862231