MIT实习前置培训笔记6---常用的React Hooks训练

前言:前面几节已经介绍了useState和useContext的Hooks,接下来介绍其它几个Hooks的使用。

一、Reducer用于统一管理状态的操作方式

以下是用useReducer实现一个加减法器的例子:

import { type } from "@testing-library/user-event/dist/type";
import React, { createContext, useContext, useReducer, useState } from "react";

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

export default function App() {

  const [state,dispatch]=useReducer(countReducer,0)
  const handleIncrement=()=>dispatch({type:"increment"})
  const handleDecrement=()=>dispatch({type:"decrement"})
  return (
    <div style={{padding:10}}>
      <button onClick={handleIncrement}>+</button>
      <span>{state}</span>
      <button onClick={handleDecrement}>-</button>
    </div>
  )
}

加减法器效果图:

二、useRef记录变更之前的值

useRef 是 React 的一个钩子,主要用于在函数组件中存储对 DOM 元素的引用或保持任何可变的数据。这个钩子在组件的整个生命周期内保持不变的引用,这对于处理不希望在渲染间发生变化的值非常有用。

下面以一个视频播放器为例,来详细描述useRef的使用:

说明

  • 视频组件:这里使用了 HTML 的 <video> 标签,并为其添加了 controls 属性,这样即便没有使用按钮控制,用户也可以用默认的播放器控件来控制视频。
  • Ref 的使用videoRef 创建后被赋给 <video> 元素的 ref 属性。这样,videoRef.current 就会指向 DOM 中的视频元素,使我们可以调用 .play().pause() 方法来控制视频。
  • 控制函数handlePlayhandlePause 函数通过 videoRef.current 直接操作视频元素,实现播放和暂停功能。
import React, { useRef } from 'react';

function VideoPlayer() {
  // 创建一个 ref 来引用视频元素
  const videoRef = useRef(null);

  // 控制视频播放
  const handlePlay = () => {
    videoRef.current.play();
  };

  // 控制视频暂停
  const handlePause = () => {
    videoRef.current.pause();
  };

  return (
    <div>
      {/* 绑定 ref 到 video 元素 */}
      <video ref={videoRef} width="320" height="240" controls>
        <source src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" type="video/mp4" />
        Your browser does not support the video tag.
      </video>
      <br />
      <button onClick={handlePlay}>Play</button>
      <button onClick={handlePause}>Pause</button>
    </div>
  );
}

export default VideoPlayer;

这个例子清晰地展示了如何使用 useRef 来操作 DOM 元素,并通过 React 组件外部的按钮控制元素行为。具体效果如下:

三、useEffect钩子

useEffect 是 React 的一个核心钩子,用于在函数组件中执行副作用操作。副作用可能包括数据获取、订阅、手动修改 DOM 等,这些都是在渲染流程之外的操作。useEffect 的功能类似于类组件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 生命周期方法的组合。

功能概述

  • 执行副作用:在组件渲染到屏幕之后执行。
  • 依赖控制:通过依赖数组来优化效率,仅在依赖项改变时重新执行。
  • 清理函数:在组件卸载前或依赖项改变前执行清理,避免内存泄漏。

使用场景

  1. 数据获取:在组件加载后从服务器请求数据。
  2. 设置订阅:如订阅外部数据源或事件监听。
  3. 手动更改 DOM:对 DOM 的操作通常是响应某些状态或属性的变化。

完整示例:数据获取

这个例子中,我将使用 useEffect 来进行数据获取。组件将从一个 API 获取数据,并将数据展示在页面上。

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

function FetchDataComponent() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // 副作用调取的 API URL
    const apiUrl = 'https://jsonplaceholder.typicode.com/posts';

    // 异步获取数据
    const fetchData = async () => {
      try {
        const response = await fetch(apiUrl);
        const data = await response.json();
        setData(data.slice(0, 5)); // 只取前五条数据
        setLoading(false); // 数据加载完成
      } catch (error) {
        console.error('Fetching data failed', error);
        setLoading(false);
      }
    };

    fetchData();

    // 可选的清理函数
    return () => {
      console.log("Cleanup if needed");
    };
  }, []); // 空依赖数组意味着这个 effect 只在组件挂载时执行一次

  return (
    <div>
      {loading ? <p>Loading...</p> : (
        <ul>
          {data.map(post => (
            <li key={post.id}>{post.title}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

export default FetchDataComponent;

效果:

先异步请求数据:

组件加载后调用副作用函数取数据:

四、useMemo钩子

useMemo 是 React 的一个钩子,用于优化性能通过记忆计算结果。这个钩子会缓存一个函数的计算结果,并在依赖项没有改变的情况下,在多个渲染周期中重用这个结果。主要用于处理那些计算成本较高的函数,以避免在每次渲染时都重新计算。

主要功能

  • 性能优化:减少不必要的计算,尤其是在渲染周期中经常执行且资源消耗较大的计算。
  • 避免计算副作用:在依赖项未变化的情况下,避免重新执行可能引起副作用的函数。
  • 参照相等性:可以用于优化子组件的渲染,当计算得到的对象被作为属性传递给子组件时,使用 useMemo 可以保持对象的引用相等,避免不必要的子组件渲染。

这里有一个简单的 useMemo 示例,用于演示如何使用这个钩子来计算数组中数字的平方和。我将使用 useMemo 来确保只有在数字数组发生变化时才重新计算平方和,避免在每次渲染时进行不必要的计算。

  • import React, { useState, useMemo } from 'react';
    
    function SumOfSquares() {
      const [numbers, setNumbers] = useState([1, 2, 3, 4]);
      const [addNumber, setAddNumber] = useState('');
    
      // 使用 useMemo 来计算平方和
      const sumOfSquares = useMemo(() => {
        console.log('Calculating sum of squares...');
        return numbers.reduce((sum, num) => sum + num * num, 0);
      }, [numbers]);
    
      const addNumberToList = () => {
        if (!isNaN(addNumber) && addNumber !== '') {
          setNumbers([...numbers, parseInt(addNumber)]);
          setAddNumber('');
        }
      };
    
      return (
        <div>
          <input
            type="text"
            value={addNumber}
            onChange={(e) => setAddNumber(e.target.value)}
            placeholder="Add a number"
          />
          <button onClick={addNumberToList}>Add Number</button>
          <div>Numbers: {numbers.join(', ')}</div>
          <div>Sum of Squares: {sumOfSquares}</div>
        </div>
      );
    }
    
    export default SumOfSquares;
    

 

效果:

 

添加一个数字6:
五、useCallback钩子

useCallback 是 React 的一个钩子,用于在组件的多次渲染间返回一个相同的回调函数引用。这个钩子接收一个内联回调和一个依赖项数组。useCallback 会返回一个记忆化的版本的回调函数,只有当一个或多个依赖项改变时,这个回调函数才会更新。

作用和用途

  1. 性能优化:防止因为回调函数的不必要重创建而导致子组件不必要的渲染,尤其是在将回调函数传递给纯组件或优化了渲染性能的组件时。
  2. 参照相等性:确保回调函数在多个渲染周期中保持相同,如果这个函数被用作其他效果或回调的依赖,则非常有用。

示例:计数器组件

下面是一个使用 useCallback 钩子的例子,该例子创建一个计数器,其中包含一个通过回调函数增加计数值的按钮。

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

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

  // 使用 useCallback 来缓存回调函数
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, []); // 依赖项为空,意味着这个函数不会因为组件内部状态的变化而重新创建

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

export default Counter;

代码说明

  • 初始化状态:使用 useState 创建一个名为 count 的状态变量。
  • 创建回调函数:使用 useCallback 创建一个名为 increment 的回调函数,该函数通过调用 setCount 来增加 count 的值。回调函数被 useCallback 缓存,只会在组件首次渲染时创建一次。
  • 渲染组件:显示当前计数值和一个按钮。点击按钮时,调用 increment 函数增加计数值。

这个例子展示了 useCallback 的基本用法,适合于需要确保回调函数在组件的多次渲染间不变时使用。这种方式有助于减少不必要的渲染和性能开销,尤其是在将回调传递给需要优化的子组件时。

至此,react的hooks就结束了~~~后面还会写一些实战的时候学到的东西~~~

  • 21
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值