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)
  • 纯函数组件没有状态,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={changeMsg}>改变文本</button> */}
      <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>
    </>
  )
}
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>  
    </>
  )
}

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

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

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

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

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

用法 createContext(defaultValue)

  • 创建上下文
  • 从一个文件导入和导出上下文
// 在任意组件外调用 createContext 创建一个上下文
import { createContext } from 'react';

const ThemeContext = createContext('light');

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

// Contexts.js
import { createContext } from 'react';

export const ThemeContext = createContext('light');
export const AuthContext = createContext(null);

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

// Button.js
import { ThemeContext } from './Contexts.js';

function Button() {
  const theme = useContext(ThemeContext);
  // ...
}

具体使用

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

在需要嵌套的顶层组件中引入此 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>
  )
}

在 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>
  )
}

在 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>
  )
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值