React 源码阅读-4_033

2019-10-11 admin

上下文 Context

上下文Context 提供了一种通过组件树传递数据的方法,无需在每个级别手动传递 props 属性。

何时使用 Context

Context 旨在共享一个组件树内可被视为 “全局” 的数据,例如当前经过身份验证的用户,主题或首选语言等;

  const context: ReactContext<T> = {
    $typeof: REACT_CONTEXT_TYPE,
    _calculateChangedBits: calculateChangedBits,
    _currentValue: defaultValue,
    _currentValue2: defaultValue,
    // Used to track how many concurrent renderers this context currently
    // supports within in a single renderer. Such as parallel server rendering.
    _threadCount: 0,
    // These are circular
    Provider: (null: any),
    Consumer: (null: any),
  };

例子:

class App extends React.Component {
  render() {
    return <Toolbar theme="dark" />;
  }
}

  // Toolbar 组件接受一个额外的“theme”属性,然后传递给 ThemedButton 组件。
  // 如果应用中每一个单独的按钮都需要知道 theme 的值,这会是件很麻烦的事,
  // 因为必须将这个值层层传递所有组件。

function Toolbar(props) {
  return (
    <div>
      <ThemedButton theme={props.theme} />
    </div>
  );
}
class ThemedButton extends React.Component {
  render() {
    return <Button theme={this.props.theme} />;
  }
}

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

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

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

// 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
// 无论多深,任何组件都能读取这个值。
// 在这个例子中,我们将 “dark” 作为当前的值传递下去。

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

class ThemedButton extends React.Component {.
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}

使用Context之前的考虑

1.Context 主要应用场景在于很多不同层级的组件需要访问同样一些的数据。请谨慎使用,因为这会使得组件的复用性变差。

如果你只是想避免层层传递一些属性,组件组合(component composition)有时候是一个比 context 更好的解决方案。

<Page user={user} avatarSize={avatarSize} />
// ... 渲染出 ...
<PageLayout user={user} avatarSize={avatarSize} />
// ... 渲染出 ...
<NavigationBar user={user} avatarSize={avatarSize} />
// ... 渲染出 ...
<Link href={user.permalink}>
  <Avatar user={user} size={avatarSize} />
</Link>

一种无需 context 的解决方案是将 Avatar 组件自身传递下去,因而中间组件无需知道 user 或者 avatarSizeprops

function Page(props) {
  const user = props.user;
  const userLink = (
    <Link href={user.permalink}>
      <Avatar user={user} size={props.avatarSize} />
    </Link>
  );
  return <PageLayout userLink={userLink} />;
}

// 现在,我们有这样的组件:
<Page user={user} avatarSize={avatarSize} />
// ... 渲染出 ...
<PageLayout userLink={...} />
// ... 渲染出 ...
<NavigationBar userLink={...} />
// ... 渲染出 ...
{props.userLink}

但是,有的时候在组件树中很多不同层级的组件需要访问同样的一批数据。Context 能让你将这些数据向组件树下所有的组件进行“广播”,所有的组件都能访问到这些数据,也能访问到后续的数据更新。使用 context 的通用的场景包括管理当前的 locale,theme,或者一些缓存数据,这比替代方案要简单的多。

React.createContext

const MyContext = React.createContext(defaultValue);

创建一个 Context 对象。当 React渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。

只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。这有助于在不使用 Provider 包装组件的情况下对组件进行测试。注意:将 undefined 传递给 Providervalue 时,consumer组件的 defaultValue 不会生效

Context.Provider

每个 Context 对象都会返回一个 Provider React 组件,它允许consumer组件订阅 context 的变化。

  context.Provider = {
    $typeof: REACT_PROVIDER_TYPE,
    _context: context,
  };

Provider 接收一个 value 属性,传递给consumer组件。一个 Provider 可以和多个consumer组件有对应关系。多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。

Providervalue 值发生变化时,它内部的所有consumer组件都会重新渲染。Provider 及其内部 consumer 组件都不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其祖先组件退出更新的情况下也能更新。

通过新旧值检测来确定变化,使用了与 Object.is 相同的算法。

img

Class.contextType

class MyClass extends React.Component {
  componentDidMount() {
    let value = this.context;
    /* 在组件挂载完成后,使用 MyContext 组件的值来执行一些有副作用的操作 */
  }
  componentDidUpdate() {
    let value = this.context;
    /* ... */
  }
  componentWillUnmount() {
    let value = this.context;
    /* ... */
  }
  render() {
    let value = this.context;
    /* 基于 MyContext 组件的值进行渲染 */
  }
}
MyClass.contextType = MyContext;

挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象。这能让你使用 this.context 来消费最近 Context 上的那个值。你可以在任何生命周期中访问到它,包括 render 函数中。

多个的情况

https://zh-hans.reactjs.org/d…

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

Context.Consumer

const Consumer = {
  $typeof: REACT_CONTEXT_TYPE,
  _context: context,
  calculateChangedBits: context._calculateChangedBits,
  };
<MyContext.Consumer>
  {value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>

这里,React 组件也可以订阅到 context 变更。这能让你在函数式组件中完成订阅 context。

这需要函数作为子元素(function as a child)这种做法。这个函数接收当前的 context 值,返回一个 React 节点。传递给函数的 value 值等同于往上组件树离这个 context 最近的 Provider 提供的 value 值。如果没有对应的 Provider,value 参数等同于传递给 createContext()defaultValue

http://react.html.cn/docs/con…

[转载]原文链接:https://segmentfault.com/a/1190000020642522

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-77069.html

文章标题:React 源码阅读-4_033

相关文章
[翻译]基于Webpack4使用懒加载分离打包React代码
原文地址:https://engineering.innovid.com/code-splitting-using-lazy-loading-with-react-redux-typescript-and-webpack-4-3ec601...
2018-03-11
2015年2月国内操作系统市场份额概况,xp占46.29%,
规则调整:2012年6月1日开始,Mac操作系统中不再包含ipad、iphone市场份额。 ...
2015-11-12
Windows Server 2003将于7月14日停服
腾讯数码讯(文心)据PCWorld网站报道,微软的Windows Server 2003操作系统将很快重蹈Windows XP停服的覆辙,对于迟迟没有升级到新版本服务器操作系统的IT主管来说,这确实是个坏消息。 微软将于7月14日叫停对W...
2015-11-12
VSCode配置react开发环境的步骤
vscode 默认配置对于 react 的 JSX 语法不友好,体现在使用自动格式化或者粘贴后默认缩进错误,尽管可以通过改变 language mode 缓解错误,但更改 language mode 后的格式化依然不够理想。 通过搭配使用 ...
2017-12-28
2014年,你是不是被这5个HTML5技术刷屏了?
如今,几乎每天都有HTML5页面的推广以及小游戏、小测试在微信上传播,用户也逐渐习惯被各种HTML5轰炸。那么在刚刚过去的一年究竟有哪些HTML5技术堪称火爆,让人们的微信频频被刷屏呢? 1、2048 2048 在4x4的棋盘上,用方向键选...
2015-11-12
2014年十大编程语言
近日,IEEE Spectrum推出了一个最流行的编程语言排行榜。排行榜筛选了12项指标,综合了10个来源(含 IEEE Xplore、Google、GitHub)的数据,最终评选出了下面这个排行榜(满分100,得分越高排名越靠前),其中的...
2015-11-11
Webpack(含 4)配置详解——从 0 配置一套开发模板
前言 源代码 熟悉 webpack 与 webpack4 配置。 webpack4 相对于 3 的最主要的区别是所谓的零配置,但是为了满足我们的项目需求还是要自己进行配置,不过我们可以使用一些 webpack 的预设值。同时 webpack...
2018-05-02
2015年4月TIOBE编程语言排行榜 JavaScript排第六位
IOBE近日发布2015年4月编程语言排行榜,前三名终于发生变化,Objective-C退出前三掉落第四位,C++势头勇猛上升4位冲进前三,Java更是一举大力夺得第一,而最让人兴奋的是JavaScript连冲9位,雄踞第六位! ...
2015-11-12
4种方法帮你的网站创建更丰富的Web体验
现在的网站已经从一个简单的文本页面开始进化了很多,我们可以制作出丰富的视觉效果来增加用户在桌面浏览器和移动浏览器的体验。 今天这篇文字就给大家分享4个实用的方法,来帮助你创建更好的Web体验。 对于那些还在用IE6的朋友,我只想说一句:go...
2016-01-13
深入理解JavaScript的React框架的原理
如果你在两个月前问我对React的看法,我很可能这样说: 我的模板在哪里?javascript中的HTML在做些什么疯狂的事情?JSX开起来非常奇怪!快向它开火,消灭它吧! 那是因为我没有理解它. 我发誓,React 无疑是在正确的轨道...
2017-03-26
回到顶部