Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

全新的 React Context API #27

Open
Hancoson opened this issue Apr 8, 2018 · 3 comments
Open

全新的 React Context API #27

Hancoson opened this issue Apr 8, 2018 · 3 comments

Comments

@Hancoson
Copy link
Owner

Hancoson commented Apr 8, 2018

在一个经典的 React 应用中,组件之间通信是常用到的技术方案。在父子组件之间通常通过 props 来传递参数,而非父子组件就比较麻烦了,要么就一级一级通过 props 传递,要么就使用 Redux or Mobx 这类状态管理的状态管理库,但是这样无疑增加了应用的复杂度。在 FEers 的期盼中,React 团队终于从 16.3.0 版本开始新增了一个新的 API Context,福音啊。好了,今天我就来一起学习一下这个新的 Context

什么时候使用 Contsxt

Context 目的是为了共享可以被认为是 React 组件“全局”树的数据。例如当前应用的主题、首选语言等等。接下来看看通过 propsContext 两种方式实现按钮组件样式参数传递方式的对比:

  • props
class App extends React.Component {
  render() {
    return <Toolbar theme="dark" />;
  }
}
Toolbar(props) {
  return (
    <div>
      <ThemedButton theme={props.theme} />
    </div>
  );
}
ThemedButton(props) {
  return <Button theme={props.theme} />;
}
  • Context
// 创建 context 实例
const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}
Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

ThemedButton(props) {
  return (
    <ThemeContext.Consumer>
      {theme => <Button {...props} theme={theme} />}
    </ThemeContext.Consumer>
  );
}

API

React.createContext

创建一个 ContextReact.createContext 提供了 {Provider,Comsumer} 两个方法,上面的代码也可以这个来写:

const {Provider,Comsumer} = React.createContext('light');

class App extends React.Component {
  render() {
    return (
      <Provider value="dark">
        {/* ... */}
      </Provider>
    );
  }
}
{/* ... */}
ThemedButton(props) {
  return (
    <Consumer>
      {/* ... */}
    </Consumer>
  );
}

Provider

这里的 Provider 类似 react-redux 中的 Provider 组件,用来注入全局的 data (允许 Consumer 订阅 Context 的变化)。一个 Provider 可以连接到多个 Consumer

Consumer

Consumer 组件,表示要消费 Provider 传递的数据(订阅 Context 的响应组件)。当 Provider 发生变化的时候,所有的 Consumer 都会被 re-rendered

结束语

Context 的引入,一定程度上可以减少不少项目对 redux 全家桶的依赖,从而降低了项目的复杂程度,何乐而不为呢~~

@Hancoson
Copy link
Owner Author

React 16+ 新的生命周期

v2-50df8407730530985712a313ae020041_r

@qumuchegi
Copy link

qumuchegi commented Oct 22, 2020

consumer 好像并没能订阅 context 的变化,只能获取初始值,是不是我用的不对?
我是这样用的:
在父组件:

import Child1 from './child1'

const defaultContext = {
  a: 0,
  setA: function (a) {
    this.a = a
  }
}

export const Context = createContext()

export default class Father extends React.Component {
  render() {
    return <Context.Provider value={defaultContext}>
        <Child1/>
    </Context.Provider>
  }
}

在子组件:

class Child1 extends React.Component {
  render() {
    const {context} = this.props
    return<div style={{backgroundColor: '#897', padding: '29px'}}>
      子组件1
      <div>a:{context.a}</div>
      <input placeholder='输入' onChange={(e) => context.setA(e.target.value)}></input>
    </div>
  }
}

export default () => <Context.Consumer>{
  (context) => {
   return <Child1 context={context}/>
  }
}</Context.Consumer>

我在子组件中调用 context.setA() 修改了 context.a,但是子组件并没有更新

@qumuchegi
Copy link

知道为啥子组件没有更新了,因为组件更新需要 state / props 变化,但是 context value 这两者都不是

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants