React的context用法

·  阅读 394

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。

数据流向下传递,由最高层级的组件注入数据,在任一子组件进行接收。

使用 context, 我们可以避免通过中间元素传递 props

**如果你只是想避免层层传递一些属性,组件组合(component composition)有时候是一个比 context 更好的解决方案。**使用场景不多,这里不再做过多的赘述,有兴趣的可以去官网看看

中文官网地址:react.docschina.org/docs/contex…

例如:

1.首先在父组件中(father.js),我们进行数据的注入:

    1)引入createContext函数

import React, {createContext } from 'react'
复制代码

    2)在父组件中把创建的 createContext暴露出去

createContxt(value),value是默认值

export const ThemeContext = createContext('light')
复制代码

   3)在父组件的render函数中进行注入:value={this.state}变量或静态值也可 

      使用 Context.Provider 来进行数据注入

<ThemeContext.Provider value="dark">
    <Child />
</ThemeContext.Provider>
复制代码

2.在任一后代组件树中(Child )进行数据的接收:

   2.1 使用 **Context.**Consumer来进行接收

1)首先引入父组件暴露的context函数

import { ThemeContext } from './father'
复制代码

2)在子组件中进行渲染,ThemeContext.Consumer

<ThemeContext.Consumer>
    {(value) => (
        <h1 style={{ color: 'green' }}>
        任一子组件接受的值Context : {value}
        </h1>
    )}
</ThemeContext.Consumer>
复制代码

   2.2 使用contextType来接收

class Child extends React.Component {
  static contextType = MyContext;
  render() {
    let value = this.context;
    /* 基于这个值进行渲染工作 */
  }
}
复制代码

3.在嵌套组件中更新 Context

从一个在组件树中嵌套很深的组件中更新 context 是很有必要的。在这种场景下,你可以通过 context 传递一个函数,使得 consumers 组件更新 context:

//----------首先创建createContext并暴露出去
//theme-context.js
export const ThemeContext = React.createContext({
  theme: themes.dark,  
  toggleTheme: () => {}
});

//----------建立一个theme-toggler-button的子组件进行值得接收
//theme-toggler-button.js
import {ThemeContext} from './theme-context';
function ThemeTogglerButton() {
  // Theme Toggler 按钮不仅仅只获取 theme 值,它也从 context 中获取到一个 toggleTheme 函数  return (    <ThemeContext.Consumer>
      {({theme, toggleTheme}) => (
        <button 
          onClick={toggleTheme}
          style={{backgroundColor: theme.background}}>
          Toggle Theme
        </button>
      )}
    </ThemeContext.Consumer>
  );
}

export default ThemeTogglerButton;

//----------app.js
//在父组件进行值得注入
import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';
export default class App extends React.Component {  constructor(props) {
    super(props);
    //toggleTheme的回调函数 注入到子组件
    this.toggleTheme = () => {
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };

    // State 也包含了更新函数,因此它会被传递进 context provider
    this.state = {      
      theme: themes.light,
      toggleTheme: this.toggleTheme,
    }}

  render() {
    // 整个 state 都被传递进 provider    
    return (
      <ThemeContext.Provider value={this.state}>        
            <ThemeTogglerButton />
      </ThemeContext.Provider>
    );
  }
}
复制代码

4.消费多个 Context

为了确保 context 快速进行重渲染,React 需要使每一个 consumers 组件的 context 在组件树中成为一个单独的节点

-----------父组件进行数据的注入
// Theme context,默认的 theme 是 “light” 值
const ThemeContext = React.createContext('light');
// 用户登录 context
const UserContext = React.createContext({
  name: 'Guest',
});

class App extends React.Component {
  render() {
    const {signedInUser, theme} = this.props;
    return (
    //多个嵌套的 Context
      <ThemeContext.Provider value={theme}>        
        <UserContext.Provider value={signedInUser}>         
             <Layout />
        </UserContext.Provider>     
     </ThemeContext.Provider>    
    );
  }
}


//------------子组件进行数据的接收
function Content() {
  // 一个组件可能会消费多个 context
    <ThemeContext.Consumer>
        {theme => (
            <UserContext.Consumer>
                 {user => (                    <ProfilePage user={user} theme={theme} />                          )}             </UserContext.Consumer>
            )}    
    </ThemeContext.Consumer>
 );
}
复制代码

注意事项

       因为 context 会使用参考标识(reference identity)来决定何时进行渲染,这里可能会有一些陷阱,当 provider 的父组件进行重渲染时,可能会在 consumers 组件中触发意外的渲染。举个例子,当每一次 Provider 重渲染时,以下的代码会重渲染所有下面的 consumers 组件,因为 value 属性总是被赋值为新的对象

class App extends React.Component {
  render() {
    return (
      <MyContext.Provider value={{something: 'something'}}>       
         <Toolbar />
      </MyContext.Provider>
    );
  }
}
复制代码

为了防止这种情况,将 value 状态提升到父节点的 state 里:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'},   
     };
  }

  render() {
    return (
      <Provider value={this.state.value}>       
         <Toolbar />
      </Provider>
    );
  }
}
复制代码
分类:
前端
标签: