React Hooks -useContext/useMemo/useCallback详解(2)

1,139 阅读3分钟

这是我参与更文挑战的第22天,活动详情查看: 更文挑战

1, useContext

1, 用法

const value = useContext(MyContext);

注意: useContext和createContext 要配合使用

2,说明

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

当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext provider 的 context value

3,举例

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemeContext = React.createContext(themes.light);

function App() {
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

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

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}

2, useMemo

1, 用法

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

2, 说明 把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

记住,传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo

如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值

  • 类似shouldComponentUpdate作用,在渲染过程中避免重复渲染的问题,当状态或者父组件传来的属性发生变化时,更新组件

useMemo就是用的memoization来提高性能的,Memoization是JavaScript中的一种缓存技术

useMemo是一个函数,有两个参数,第一个参数是个:函数,第二个参数是个数组

useMemo(()=>{}, [默认可以不写])

useMemouseEffect的执行时间不同,useEffect是在componentDidMount之后执行的,而useMemo是在组件渲染过程中执行的。

1,如果第二个参数不写,回调函数一定会执行
2,如果第二个参数为空,回调函数不执行
3,如果第二个参数为prop或者state, 依赖发生变化

3, 举例

import './App.css';
import React , { useState, useMemo, useEffect } from 'react'
import { Button} from '@material-ui/core'

function App() {
    let [count, setCount] = useState(0)
    let [num, setNum] = useState(0)
    
    useEffect(() => {
        console.log('useEffect')
    })
    let res = useMemo(() => {
        console.log('useMemo')
        return {count, num}
    },[count, num])
  return (
    <>
     <h2>父组件状态=count{res.count}----num{res.num}</h2>
     <Button
      variant="contained"
      color="primary"
      onClick={()=> {
          setCount(count +1)
      }}
     >chang-count</Button>
      <Button
      variant="contained"
      color="primary"
      onClick={()=> {
          setNum(num +1)
      }}
     >chang-num</Button>
     </>
  );
}

export default App;

3, useCallback

1, 用法

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

返回一个 memoized 回调函数。

2, 说明

把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。

useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

3, 作用

避免组件重复渲染,提高性能,可以控制组件什么时候需要更新

4,不同

同样用到缓存技术,和useMemo不同的是, useMemo缓存的是值,useCallback缓存的是函数,是个函数就可以执行

useCallback()有两个参数, 第一个参数是一个函数,第二个参数是一个数组

useCallback(()=>{}, [可以不写])

注意:

const callback = useCallback(()=>{}, [])

callback是一个函数,可以直接callback()运行

1, 如果第二个参数没有写,默认状态改变,组件渲染的时候执行, 
2, 如果第二个参数是空数组,默认只是第一次组件渲染的时候执行
3, 如果第二个参数是state, 默认监听这个state的变化而执行

5, 举例

import './App.css';
import React , { useState, useEffect, useCallback } from 'react'
import { Button} from '@material-ui/core'

function App() {
    let [count, setCount] = useState(0)
    
    useEffect(() => {
        console.log('useEffect')
    },)
    let callback = useCallback(() => {
        console.log('usecallBack', count)
        return count
    },[count])
  return (
    <>
     <h2>父组件状态=count{count}</h2>
     <h2>callback=:{callback()}</h2>
     <Button
      variant="contained"
      color="primary"
      onClick={()=> {
          setCount(count +1)
      }}
     >chang-count</Button>
     </>
  );
}

export default App;