您现在的位置是:首页 >其他 >React Hooks简介网站首页其他

React Hooks简介

东方小虾米 2024-08-26 12:01:03
简介React Hooks简介

useState

最常见的React Hook。

const [state, setState] = useState(initialState);

useState接受一个初始状态值作为参数,并返回一个数组,数组的第一个元素是当前状态值,第二个元素是一个函数,用于更新状态值。当我们调用这个更新函数时,React会重新渲染组件,并将新的状态值传递给组件。

存在两个原因使得普通局部变量的变化不可见:

  1. 更改局部变量不会触发渲染。 React 没有意识到它需要使用新数据再次渲染组件。
  2. 局部变量无法在多次渲染中持久保存。 当 React再次渲染这个组件时,它会从头开始渲染——不会考虑之前对局部变量的任何更改。(又变回了初始状态)

要使用新数据更新组件,需要做两件事:

  1. 保留 渲染之间的数据。
  2. 触发 React 使用新数据渲染组件(重新渲染)。

useState Hook 提供了这两个功能:

  1. State 变量 用于保存渲染间的数据。
  2. State setter 函数 更新变量并触发 React 再次渲染组件。

当你调用 useState 时,你是在告诉 React 你想让这个组件记住一些东西。

对于需要管理组件内部状态的情况,使用 useState 是一个很好的选择。举例来说,当组件需要根据用户交互更新某些数据时,就可以使用 useState 来存储该数据。具体包括但不限于以下几种情况:

  1. 组件需要存储用户的输入数据(例如表单)。
  2. 组件需要存储数据的加载状态。
  3. 组件需要存储一些 UI 标志。
  4. 组件需要在内部跟踪某些状态并基于状态更改渲染不同的视图。

使用 useState 对状态的管理能够帮助你更容易地维护组件的状态,并且可以避免在组件之间共享状态时可能产生的不必要的副作用或耦合。

state 可以保存任何类型的 JavaScript 值,包括对象。但是你不应该直接改变你在 React state 中持有的对象。相反,当您想要更新一个对象时,您需要创建一个新的对象(或者复制一个现有的对象),然后设置 state 以使用该副本。可以使用useImmer更方便的管理对象。

useCallback

useCallback是React提供的一个Hooks函数,它用于缓存函数,避免函数的不必要重复创建,从而提高组件的性能。

const cachedFn = useCallback(fn, dependencies)

它接收两个参数:第一个参数是一个函数,第二个参数是一个依赖项数组。

当依赖项数组中的任意一个值发生变化时,useCallback会重新计算并返回一个新的函数,否则会返回上一次缓存的函数。使用useCallback可以避免在每次组件重新渲染时都创建新的回调函数,从而避免了子组件的不必要重新渲染,提高了应用的性能。

普通函数性能差的原因:

我们经常会给一些元素绑定事件,或者是将一些函数通过属性的形式传递给子组件。在函数式组件中,如果不经任何处理的函数通过属性的形式传递给子组件,那么,一旦父组件的任意状态发生变化进行重新渲染时,会因为每次的函数都是一个新的引用而**导致子组件因为属性的改变而重新渲染。**这可能会导致性能问题。

useCallback 用来缓存通过函数依赖项计算得到的回调函数,以便在依赖项没有变化时避免重复渲染。如果依赖项数组不变,那么每次渲染组件时,useCallback 返回的都是相同的回调函数的引用,这时就可以避免不必要的重复渲染。

使用useCallback时需要注意以下几点:

  1. 如果依赖项数组为空数组[],则useCallback只会在组件第一次渲染时计算并返回一个函数,之后不会再重新计算。
  2. 如果依赖项数组不传递,则useCallback会在每次组件重新渲染时都重新计算并返回一个新的函数,这会导致性能问题。
  3. useCallback返回的函数是一个引用类型,因此在使用时需要注意引用相等性问题。如果使用了useCallback返回的函数作为子组件的props,可以使用React.memo(React.memo打包子组件 ——只要 props 不发生改变,就不会重复渲染。)进行优化,避免不必要的子组件重新渲染。
  4. memo返回的是函数,但不会调用函数。
  5. React 将使用 Object.is比较算法将每个依赖项与其先前的值进行比较。

useMemo

useMemo用于在函数组件中进行性能优化,避免不必要的计算。

const cachedValue = useMemo(calculateValue, dependencies)

useMemo接收两个参数:第一个参数是一个函数,用于进行计算;第二个参数是一个依赖项数组,用于指定哪些变量的变化会触发重新计算。如果依赖项数组中的任意一个值发生变化,useMemo会重新计算并返回一个新的值,否则会返回上一次缓存的值。

使用useMemo时需要注意以下几点:

  1. 如果依赖项数组为空数组[],则useMemo只会在组件第一次渲染时计算并返回一个值,之后不会再重新计算。
  2. 如果依赖项数组不传递,则useMemo会在每次组件重新渲染时都重新计算并返回一个新的值,这会导致性能问题。
  3. useMemo返回的值是一个引用类型,因此在使用时需要注意引用相等性问题。如果使用了useMemo返回的值作为子组件的props,可以使用React.memo进行优化,避免不必要的子组件重新渲染。
  4. 不要滥用useMemo,只有在需要进行复杂计算或者渲染大量数据时,才需要使用useMemo进行性能优化。

useMemo、useCallback、useEffect的区别

useCallbackuseMemo(() => fn, deps) 等价于 useCallback(fn, deps)。主要区别是 React.useMemo 将调用 fn 函数并返回其结果,而 React.useCallback 将返回 fn 函数而不调用它。简单来说 useMemo(用作缓存一个值),useCallback(用来缓存一个函数) 二者都是避免子组件被重复渲染。useEffect不返回任何东西,只是在适当的时机执行代码。

useEffect - is used to run side effects in the component when something changes. useEffect does not return you anything. It just runs a piece of code in the component.

useCallback - Whereas useCallback returns a function, it does not execute the code actually. It is important to understand that functions are objects in Javascript. If you don’t use useCallback, the function you define inside the component is re-created whenever the component rebuilds.

https://stackoverflow.com/questions/68172724/usecallback-vs-useeffect-in-react
https://juejin.cn/post/7008433550307360798#heading-0

useEffect

useEffect用于在函数组件中处理副作用。(synchronize a component with an external system.

useEffect(setup, dependencies?)

useEffect接收两个参数:第一个参数是一个函数,用于执行副作用操作;第二个参数是一个依赖项数组,用于指定哪些变量的变化会触发副作用操作。如果依赖项数组中的任意一个值发生变化,useEffect会重新执行副作用操作,否则会跳过副作用操作。

副作用是指对组件外部环境产生影响的操作(没有发生在数据向视图转换过程中的逻辑),例如访问网络、修改DOM、订阅事件等。使用 useEffect,我们可以在组件挂载、更新或卸载时执行副作用操作https://react.docschina.org/learn/synchronizing-with-effects

Effects 可以让你声明由渲染过程自然引起的副作用,而不是事件函数引起的副作用。

  1. 原先在函数组件内( React 渲染阶段)改变 dom 、发送 ajax 请求以及执行其他包含副作用的操作都是不被允许的,因为这可能会产生莫名其妙的 bug 并破坏 UI 的一致性。
  2. useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。

使用useEffect需要注意以下几点:

  1. 如果依赖项数组为空数组[],则useEffect只会在组件挂载和卸载时执行副作用操作,不会在组件更新时执行。

  2. 如果依赖项数组不传递,则useEffect会在每次组件挂载、更新、卸载时都执行副作用操作,这会导致性能问题。

  3. 在副作用操作中,:**要么返回一个能清除副作用的函数,**用于在组件卸载、依赖项数组发生变化时清除副作用操作。要么就不返回任何内容。

  4. 不要滥用useEffect,只有在需要进行副作用操作时,才需要使用useEffect。

useContext

让我们在函数组件中使用React的Context,避免了在组件树中一层层地传递props的繁琐过程。

const value = useContext(SomeContext)

使用useContext时,我们需要先创建一个Context对象,并通过Provider组件将数据传递给子组件。然后在子组件中使用useContext获取Context中的数据。

使用useContext的步骤如下:

  1. 创建一个Context对象。
const MyContext = React.createContext(defaultValue);
  1. 在父组件中使用Context.Provider组件将数据传递给子组件。
<MyContext.Provider value={/* 数据 */}> <ChildComponent /> </MyContext.Provider>
  1. 在子组件中使用useContext获取Context中的数据。
const data = useContext(MyContext);

需要注意的是,当Context中的数据发生变化时,使用该Context的组件会重新渲染。因此,使用Context时需要注意性能问题。使用 memo 来跳过重新渲染并不妨碍子级接收到新的 context 值。

当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。

useReducer

相比于 useState,useReducer 更加适合管理状态逻辑复杂且包含多个子值的组件中的状态,例如表单的状态管理。useReducer 的使用方法类似于 Redux 中的 Reducer。

useReducer 接收两个参数:reducer 和 initialState。

reducer 是一个纯函数,它接收两个参数,分别是**当前 state 和 action。**和 Redux 中的 Reducer 一样,reducer 必须是一个纯函数,接收一个旧的 state 和一个 action 的对象,根据 action.type 返回一个新的 state,或者不做任何改变返回原有的 state。initialState 是状态的初始值。

useReducer 的返回值是一个包含两个元素的数组:

[state, dispatch] = useReducer(reducer, initialState);
  • state:用来存储当前的组件状态。
  • dispatch:是一个函数,用来向 reducer 发送 action。dispatch 接收一个 action 的对象,会根据 action.type 来判断需要更新的状态。

使用useReducer的基本步骤如下:

  1. 定义reducer函数,它接收当前状态和一个action对象,根据action的类型来更新状态,最后返回新的状态。

  2. 在组件中使用useReducer,传入reducer函数和初始状态,得到当前状态和dispatch函数。

  3. 在组件中使用dispatch函数来触发状态更新,dispatch函数接收一个action对象,根据action的类型来更新状态。

下面是一个简单的例子,展示如何使用useReducer来管理一个计数器的状态:

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();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}

useRef

useRef({}) 用于创建一个 ref 对象,这个对象可以用来保存任意可变值。在给 ref 对象赋值时,这个值不会触发组件的重新渲染。

在某些时候,我们可能需要在组件间共享一些数据,而不想因为这些数据的变化而重新渲染组件。

const ref = useRef(initialValue)

使用useRef时,我们可以通过ref.current来访问和修改存储在ref中的值。

创建 ref 对象的语法为:

c

onst refObject = useRef(initialValue);

// 其中,initialValue 为初始值,可以是任意类型的值。

// 创建好 ref 对象后,可以使用 refObject.current 来获取和更新 ref 对象保存的值。

const refObject = useRef(initialValue); 
// 获取 ref 
const currentValue = refObject.current; 
// 更新 ref 
refObject.current = newValue;

需要注意:

  1. useRef返回的是一个包含current属性的对象,而不是一个简单的值。因此,在访问和修改存储在ref中的值时,需要使用ref.current属性。斜体样式

  2. 修改ref中的值并不会触发组件的重新渲染,React 不知道你何时改变它,因为 ref 是一个普通的 JavaScript 对象。因此,如果需要在组件中使用ref中的值,需要使用useState或useReducer等Hook来触发组件的重新渲染。

  3. useRef可以用来存储任何可变的值,而不仅仅是DOM元素的引用。但是,需要注意避免在ref中存储过多的状态,以避免引起内存泄漏等问题。

  4. 除了初始化外不要在渲染期间写入 或者读取 ref.current。这会使你的组件的行为不可预测。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。