React的hooks---useContext

Context 提供了一个无需为每层组件手动添加 props ,就能在组件树间进行数据传递的方法,useContext 用于函数组件中订阅上层 context 的变更,可以获取上层 context 传递的 value prop 值

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

复制代码
const value = useContext(MyContext);

使用:

复制代码
import React, { useContext, useState } from 'react';

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

// 为当前 theme 创建一个 context
const ThemeContext = React.createContext();

export default function Toolbar(props) {
  const [theme, setTheme] = useState(themes.dark);

  const toggleTheme = () => {
    setTheme(currentTheme => (
      currentTheme === themes.dark
        ? themes.light
        : themes.dark
    ));
  };

  return (
    // 使用 Provider 将当前 props.value 传递给内部组件
    <ThemeContext.Provider value={{theme, toggleTheme}}>
      <ThemeButton />
    </ThemeContext.Provider>
  );
}

function ThemeButton() {
  // 通过 useContext 获取当前 context 值
  const { theme, toggleTheme } = useContext(ThemeContext);
  
  return (
    <button style={{background: theme.background, color: theme.foreground }} onClick={toggleTheme}>
      Change the button's theme
    </button>
  );
}

等价 class的示例,如下:

useContext(MyContext) 相当于 class 组件中的 static contextType = MyContext 或者 <MyContext.Consumer>

useContext 并没有改变消费 context 的方式,它只为我们提供了一种额外的、更漂亮的、更漂亮的方法来消费上层 context。在将其应用于使用多 context 的组件时将会非常有用

复制代码
import React from 'react';

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

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

function ThemeButton() {
  return (
    <ThemeContext.Consumer>
      {
        ({theme, toggleTheme}) => (
          <button style={{background: theme.background, color: theme.foreground }} onClick={toggleTheme}>
            Change the button's theme
          </button>
        )
      }
    </ThemeContext.Consumer>
  );
}

export default class Toolbar extends React.Component {
  constructor(props) {
    super(props);
    
    this.state = {
      theme: themes.light
    };

    this.toggleTheme = this.toggleTheme.bind(this);
  }

  toggleTheme() {
    this.setState(state => ({
      theme:
        state.theme === themes.dark
          ? themes.light
          : themes.dark
    }));
  }

  render() {
    return (
      <ThemeContext.Provider value={{ theme: this.state.theme, toggleTheme: this.toggleTheme }}>
        <ThemeButton />
      </ThemeContext.Provider>
    )
  }
}

优化消费 context 组件:

调用了 useContext 的组件都会在 context 值变化时重新渲染,为了减少重新渲染组件的较大开销,可以通过使用 memoization 来优化

假设由于某种原因,您有 AppContext,其值具有 theme 属性,并且您只想在 appContextValue.theme 更改上重新渲染一些 ExpensiveTree

  1. 方式1: 拆分不会一起更改的 context

  2. 当不能拆分 context 时,将组件一分为二,给中间组件加上 React.memo

  3. 返回一个内置 useMemo 的组件

    function Button() {
    // 把 theme context 拆分出来,其他 context 变化时不会导致 ExpensiveTree 重新渲染
    let theme = useContext(ThemeContext);
    return <ExpensiveTree className={theme} />;
    }

    function Button() {
    let appContextValue = useContext(AppContext);
    let theme = appContextValue.theme; // 获取 theme 属性
    return <ThemedButton theme={theme} />
    }

    const ThemedButton = memo(({ theme }) => {
    // 使用 memo 尽量复用上一次渲染结果
    return <ExpensiveTree className={theme} />;
    });

    function Button() {
    let appContextValue = useContext(AppContext);
    let theme = appContextValue.theme; // 获取 theme 属性

    return useMemo(() => {
    // The rest of your rendering logic
    return <ExpensiveTree className={theme} />;
    }, [theme])
    }

相关推荐
翻滚吧键盘13 分钟前
vue绑定一个返回对象的计算属性
前端·javascript·vue.js
苦夏木禾18 分钟前
js请求避免缓存的三种方式
开发语言·javascript·缓存
超级土豆粉26 分钟前
Turndown.js: 优雅地将 HTML 转换为 Markdown
开发语言·javascript·html
秃了也弱了。32 分钟前
Chrome谷歌浏览器插件ModHeader,修改请求头,开发神器
前端·chrome
乆夨(jiuze)1 小时前
记录H5内嵌到flutter App的一个问题,引发后面使用fastClick,引发后面input输入框单击无效问题。。。
前端·javascript·vue.js
忧郁的蛋~1 小时前
HTML表格导出为Excel文件的实现方案
前端·html·excel
小彭努力中1 小时前
141.在 Vue 3 中使用 OpenLayers Link 交互:把地图中心点 / 缩放级别 / 旋转角度实时写进 URL,并同步解析显示
前端·javascript·vue.js·交互
然我2 小时前
别再只用 base64!HTML5 的 Blob 才是二进制处理的王者,面试常考
前端·面试·html
NanLing2 小时前
【纯前端推理】纯端侧 AI 对象检测:用浏览器就能跑的深度学习模型
前端
呆呆的心2 小时前
前端必学:从盒模型到定位,一篇搞定页面布局核心 🧩
前端·css