前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React 设计模式 0x3:Ract Hooks

React 设计模式 0x3:Ract Hooks

作者头像
Cellinlab
发布2023-05-17 21:06:42
1.6K0
发布2023-05-17 21:06:42
举报
文章被收录于专栏:Cellinlab's Blog

学习如何轻松构建可伸缩的 React 应用程序:Ract Hooks

# React Hooks

React Hooks 是在函数式组件中使用的生命周期方法,React Hooks 在 React 16.8 中被引入。在类组件中的生命周期方法已被合并成 React Hooks,React Hooks 无法在类组件中使用。

其中一些内置的 React Hooks 包括以下几个:

  • useState
  • useReducer
  • useEffect
  • useLayoutEffect
  • useMemo
  • useCallback
  • useRef
  • useContext

在使用 React Hooks 时,需要遵循一些规则:

  • Hooks 只能在函数式组件中调用
  • Hooks 必须从顶层调用,不能在循环、条件语句等内部调用
  • 可以创建自己的 Hooks,但必须遵循前面两条规则

# useState

useState 方法是常用的 React Hooks 之一。该 Hook 被归类为 React 中的受控组件中,useState 方法设置了一个初始值,可以随着用户执行操作而更新。

代码语言:javascript
复制
import React, { useState } from "react";

function Example() {
  // 声明一个新的叫做 "count" 的 state 变量
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

export default Example;

# useReducer

useReducer 方法是常用的 React Hooks 之一。当应用程序中存在复杂的状态更改时,可以使用此 Hook,类似于 useState,但是需要发送 action 来更新状态:

代码语言:javascript
复制
import React, { useReducer } from "react";

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

const initialState = { count: 0 };

function Example() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
    </>
  );
}

export default Example;

# useEffect

useEffect 方法是常用的 React Hooks 之一。useEffect 有两个参数(箭头函数和可选的依赖项数组),用于异步操作。

依赖项数组是可选的,不传入数组时,回调函数会在每次渲染后执行,传入空数组时,回调函数只会在组件挂载和卸载时执行。依赖项数组可以接受任意数量的值,这意味着对于依赖项数组中更改的任何值,useEffect 方法将再次运行。

useEffect 箭头函数支持返回一个函数,该函数会在组件卸载时执行,用于清理定时器、取消事件监听等。

通常在组件挂载之前进行 API 调用时,会使用 useEffect

代码语言:javascript
复制
import React, { useState, useEffect } from "react";

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

  useEffect(() => {
    // 使用浏览器的 API 更新页面标题
    document.title = `You clicked ${count} times`;
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

export default Example;

# useLayoutEffect

useLayoutEffect 是 React Hooks 提供的一个用于执行副作用操作的 Hook,它与 useEffect 相似,但有一些区别。

useEffect 一样,useLayoutEffect 也会在组件渲染之后执行,但是它会在浏览器 layoutpaint 之前同步执行。这意味着 useLayoutEffect 中的任何操作都将在浏览器更新 DOM 之前执行,这使得它适用于需要精确控制渲染结果的情况。

useEffect 不同的是,useLayoutEffect 不会异步执行,这意味着它会阻塞渲染过程,直到它完成。因此,它的性能比 useEffect 差,特别是在执行昂贵操作的情况下。

使用 useLayoutEffect 的场景通常是需要在浏览器更新 DOM 前同步计算布局或者执行某些 DOM 操作。如果没有必要进行同步的操作,建议使用 useEffect 来代替,以获得更好的性能和更流畅的用户体验。

代码语言:javascript
复制
import React, { useState, useLayoutEffect } from "react";

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

  useLayoutEffect(() => {
    // 使用浏览器的 API 更新页面标题
    document.title = `You clicked ${count} times`;
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

export default Example;

# useMemo

useMemo 用于在组件重新渲染时缓存计算结果,它会缓存一个计算的返回值。可用于性能优化,因为它会缓存计算出的值,并在依赖项数组中的值不改变时返回该值。如果这些值发生变化,那么 useMemo 就会重新运行,然后返回新计算出的值。

代码语言:javascript
复制
import React, { useState, useMemo } from "react";

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

  const expensive = useMemo(() => {
    let sum = 0;
    for (let i = 0; i < count; i++) {
      sum += i;
    }
    return sum;
  }, [count]);

  return (
    <div>
      <p>
        You clicked {count} times, and sum is {expensive}
      </p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

export default Example;

# useCallback

useCallback 主要用于避免在每次渲染时都重新创建函数。

在 React 中,当父组件重新渲染时,所有的子组件也会重新渲染。如果子组件的某个函数作为 props 传递给子组件,而父组件重新渲染时,这个函数会被重新创建。这可能会导致不必要的渲染,因为即使没有必要更新组件,子组件也会重新渲染。这时就可以使用 useCallback 来优化性能。

useCallback 接收两个参数:回调函数和一个依赖项数组。当依赖项数组中的任何一个值发生变化时,回调函数就会重新生成。这意味着当 useCallback 返回的函数被传递给子组件时,只有在依赖项变化时才会重新生成。

代码语言:javascript
复制
import React, { useState, useCallback } from "react";

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

  const handleClick = useCallback(() => {
    console.log(count);
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
      <Child onClick={handleClick} />
    </div>
  );
}

function Child({ onClick }) {
  console.log("Child render");
  return <button onClick={onClick}>Click me</button>;
}

export default Example;

# useRef

useRef 用于在函数组件中创建一个持久化的引用变量,该变量的值在组件重新渲染时不会被重置。useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数(即初始值),可以通过对 current 属性的修改来更新其值。与 useState 的主要区别在于,useState 的状态更新会触发组件重新渲染,而 useRef 的引用更新不会。

例如,可以使用 useRef 存储上一次的状态值,以便在下一次状态更新时进行比较,从而避免不必要的副作用。

useRef 方法主要用于以下两个方面:

指向 DOM 中的一个元素

代码语言:javascript
复制
import React, { useRef } from "react";

function Example() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={handleClick}>Focus the input</button>
    </div>
  );
}

export default Example;

存储一些不需要触发重新渲染的变量或状态值

代码语言:javascript
复制
import React, { useState, useRef } from "react";

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

  const handleClick = () => {
    prevCountRef.current = count;
    setCount(count + 1);
  };

  return (
    <div>
      <p>
        Now: {count}, before: {prevCountRef.current}
      </p>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}

export default Example;

# useContext

useContext 用于访问在 React.createContext 中创建的上下文对象。它允许在 React 组件之间共享数据,而不需要通过多层逐层 props 传递数据。

useContext 接受一个上下文对象(通过 React.createContext 创建),并返回该上下文的当前值。在组件渲染期间,当上下文的值发生更改时,React 将重新渲染组件。

代码语言:javascript
复制
import React, { useContext, createContext } from "react";

const ThemeContext = createContext("light");

const Comp1 = () => {
  const theme = useContext(ThemeContext);
  return <div>{theme}</div>;
};

const Comp2 = () => {
  const theme = useContext(ThemeContext);
  return <div>{theme}</div>;
};

function Example() {
  return (
    <ThemeContext.Provider value="dark">
      <Comp1 />
      <Comp2 />
    </ThemeContext.Provider>
  );
}

export default Example;

# 自定义 Hooks

可以编写自己的 Hooks,这些 Hooks 是以 use 开头的函数,并且遵循之前提到的 React Hooks 的相同原则。

代码语言:javascript
复制
import React, { useState, useEffect } from "react";

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

function Example() {
  const isOnline = useFriendStatus(0);

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

export default Example;
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023/2/5,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # React Hooks
    • # useState
      • # useReducer
        • # useEffect
          • # useLayoutEffect
            • # useMemo
              • # useCallback
                • # useRef
                  • # useContext
                  • # 自定义 Hooks
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档