React Hooks常规使用

useState

useState 第一个值用来取值, 第二个值为一个方法,用来赋值和更新视图

import React, {
      useState } from 'react';

const Hooks = (): any => {
     
    const [msg, setMsg] = useState<string>('啥也be是');
	
	const Click = (): void => {
     
		setMsg(Math.random().toString())
	}

    return (
        <>
            <p onClick={
     () => Click()}>{
      msg }</p>
        </>
    )
}

export default Hooks

useEffect

有时候,我们只想在 React 更新 DOM 之后运行一些额外的代码。比如发送网络请求,手动变更 DOM,记录日志,这些都是常见的无需清除的操作。因为我们在执行完这些操作之后,就可以忽略他们了。

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

function Example() {
     
  const [count, setCount] = useState(0);

  useEffect(() => {
     
    document.title = `You clicked ${
       count} times`;
  });

  return (
    <div>
      <p>You clicked {
     count} times</p>
      <button onClick={
     () => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
  • useEffect 做了什么? 通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。在这个 effect 中,我们设置了document 的 title 属性,不过我们也可以执行数据获取或调用其他命令式的 API。

  • 为什么在组件内部调用 useEffect? 将 useEffect 放在组件内部让我们可以在 effect 中直接访问 count state 变量(或其他 props)。我们不需要特殊的 API 来读取它 —— 它已经保存在函数作用域中。Hook 使用了 JavaScript 的闭包机制,而不用在 JavaScript 已经提供了解决方案的情况下,还引入特定的 React API。

  • useEffect 会在每次渲染后都执行吗? 是的,默认情况下,它在第一次渲染之后和每次更新之后都会执行。(我们稍后会谈到如何控制它。)你可能会更容易接受 effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。

清除副作用
你可能认为需要单独的 effect 来执行清除操作。但由于添加和删除订阅的代码的紧密性,所以 useEffect 的设计是在同一个地方执行。如果你的 effect 返回一个函数,React 将会在执行清除操作时调用它:

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

function FriendStatus(props) {
     
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
     
    function handleStatusChange(status) {
     
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
     
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
     
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

为什么要在 effect 中返回一个函数? 这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数。如此可以将添加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。

React 何时清除 effect? React 会在组件卸载的时候执行清除操作。正如之前学到的,effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行当前 effect 之前对上一个 effect 进行清除。

useLayoutEffect

其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

尽可能使用标准的 useEffect 以避免阻塞视觉更新。

useContext

  • 接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的
    context 值由上层组件中距离当前组件最近的 的 value prop 决定。

  • 当组件上层最近的 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value 值。即使祖先使用 React.memo 或 shouldComponentUpdate,也会在组件本身使用 useContext 时重新渲染。

  • 调用了 useContext 的组件总会在 context 值变化时重新渲染。如果重渲染组件的开销较大,你可以 通过使用 memoization 来优化。

import React, {
      useState, useContext } from 'react';

interface listType {
     
    name: string
}

let ThemeContext: any = null

const Hooks = (): any => {
     
    const [list, setList] = useState<Array<listType>>([
        {
     
            name: 'this is a hook'
        },
        {
     
            name: '张无忌'
        },
        {
     
            name: '梓曦'
        },
    ]);

    ThemeContext = React.createContext(list);

    const Click = (): void => {
     
        let arr: Array<listType> = JSON.parse(JSON.stringify(list))
        arr.push({
      name: '什么也不是' })
        setList(arr)
    }

    return (
        <>
            <p onClick={
     () => Click()}>改变他</p>
            <ul>
                {
     
                    list.map((item: listType, index: number) => {
     
                        return(
                            <li key={
     index}>{
      item.name }</li>
                        )
                    })
                }
            </ul>
            <ThemeContext.Provider value={
     list}>
                <Toolbar></Toolbar>
            </ThemeContext.Provider>
        </>
    )
}

function Toolbar() {
     
    return (
        <div>
            <ThemedButton />
        </div>
    );
}

function ThemedButton() {
     
    let list: any = useContext(ThemeContext);
    return (
        <ul>
            {
     
                list.map((item: listType, index: number) => {
     
                    return(
                        <li key={
     index}>{
      item.name }</li>
                    )
                })
            }
        </ul>
    );
}

export default Hooks

useReducer

  • useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的state 以及与其配套的 dispatch 方法。(如果你熟悉 Redux 的话,就已经知道它如何工作了。)

  • 在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。并且,使用 useReducer 还能给那些会触发深更新的组件做性能优化,因为你可以向子组件传递 dispatch 而不是回调函数 。

import React, {
      useReducer } from 'react';

const stateObj: any = {
     
    msg: '什么也be是'
}

const reducer = (state: any, action: any): any => {
     
    switch (action.type) {
     
        case 'ALTER':
            state.msg = action.info
            return {
      ...state }
        default: 
        return state
    }
}



const Hooks = (): any => {
     
    const [state, dispatch] = useReducer(reducer, stateObj)
    const Click = (): void => {
     
        dispatch({
      type: 'ALTER', info: '我要替换你' })
    }

    return (
        <>
            <p>{
      state.msg }</p>
            <p onClick={
     () => Click()} style={
     {
     cursor: 'pointer'}}>alter</p>
            <Element dispatch={
     dispatch}></Element>
        </>
    )
}

const Element = (props: any): any => {
     
    const Click = (): void => {
     
        props.dispatch({
      type: 'ALTER', info: '我是组件二' })
    }
    
    return (
        <>
            <p onClick={
     () => Click()} style={
     {
     cursor: 'pointer'}}>组件二</p>
        </>
    )
}

export default Hooks

useCallback

  • useCallback 可以说是 useMemo 的语法糖,能用 useCallback 实 现的,都可以使用 useMemo, 常用于react的性能优化。在 react 中我们经常面临一个子组件渲染优化的问题,尤其是在向子组件传递函数props时,每次 render 都会创建新函数,导致子组件不必要的渲染,浪费性能,这个时候,就是 useCallback 的用武之地了,useCallback 可以保证,无论 render 多少次,我们的函数都是同一个函数,减小不断创建的开销。
  • callback是一个函数用于处理逻辑
  • array 控制useCallback重新执⾏的数组,array改变时才会重新执⾏useCallback
    1、不传数组,每次更新都会重新计算
    2、空数组,只会计算一次
    3、依赖对应的值,对应的值发生变化重新计算
  • useCallback返回值是callback本身(useMemo返回的是callback函数的返回值)
import React, {
      useState, useCallback } from 'react';

const Hooks = (): any => {
     
    const [msg, setMsg] = useState<string>('啥也be是');
    
    const callback = useCallback((): string => {
     
        return msg
    }, [msg])
    
    const Click = (): void => {
     
		setMsg(Math.random().toString())
	}

    return (
        <>
            <p onClick={
     () => Click()} className="banOnSelected">{
      callback() }</p>
        </>
    )
}

export default Hooks

useMemo

  • 把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。
  • 记住,传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo。
  • 如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。
  • 你可以把 useMemo 作为性能优化的手段,但不要把它当成语义上的保证。将来,React 可能会选择“遗忘”以前的一些 memoized 值,并在下次渲染时重新计算它们,比如为离屏组件释放内存。先编写在没有 useMemo 的情况下也可以执行的代码 —— 之后再在你的代码中添加 useMemo,以达到优化性能的目的。
import React, {
      useState, useCallback, useMemo } from 'react';

const Hooks = (): any => {
     
    const [msg, setMsg] = useState<string>('啥也be是');
    const [state, setState] = useState<string>('useState');
    
    const callback = useCallback((): string => {
     
        return msg
    }, [msg])

    const memo = useMemo(() => {
     
        return state
    }, [state])
    
    const Click = (): void => {
     
        setState(state + '=-=')
		setMsg(Math.random().toString())
	}

    return (
        <>
            <p onClick={
     () => Click()} className="banOnSelected">{
      callback() }</p>
            <p onClick={
     () => Click()} className="banOnSelected">{
      memo }</p>
        </>
    )
}

export default Hooks

useRef

  • useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref对象在组件的整个生命周期内保持不变。

  • 本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。

  • 你应该熟悉 ref 这一种访问 DOM 的主要方式。如果你将 ref 对象以

  • 然而,useRef() 比 ref 属性更有用。它可以很方便地保存任何可变值,其类似于在 class 中使用实例字段的方式。

  • 这是因为它创建的是一个普通 Javascript 对象。而 useRef() 和自建一个 {current: …} 对象的 唯一区别是,useRef 会在每次渲染时返回同一个 ref 对象。

  • 请记住,当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。

用来操作元素时

import React, {
      useRef } from 'react';

const Hooks = (): any => {
     
    const div = useRef<any>(null)
    
    const divClick = (): void => {
     
        if(div && div.current) {
     
            div.current.style.color = 'skyblue'
        }
    }

    return (
        <>
            <div onClick={
     () => divClick()} ref={
     div}>this is a div</div>
        </>
    )
}

export default Hooks

还可以用来当state时

import React, {
      useRef } from 'react';

const Hooks = (): any => {
     
    const state = useRef<any>(['一', '二', '三', '四', '五', '六', '七'])
    const [ msg, setMsg ] = useState<string>('')
    
    const divClick = (): void => {
     
        console.log(state.current) //['一', '二', '三', '四', '五', '六', '七']
        state.current.pop()
        console.log(state.current) //['一', '二', '三', '四', '五', '六']
        //但此时视图是不会更新的,如果想要视图更新,需使用一个useState的setState方法
        //eg: setMsg('什么也be是'),此时视图才会更新
    }

    return (
        <>
            <div onClick={
     () => divClick()} ref={
     div}>this is a div</div>
        </>
    )
}

export default Hooks

你可能感兴趣的:(reactjs)