text: exports.ids=[70],exports.modules={327:function(s,a,n){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.content='<h2 id="h2-1">Context</h2>\n<p>在使用React时，很容易在自定义的React组件之间跟踪数据流。当监控一个组件时，可以监控到那些props被传递进入组件了，这非常有利于了解数据流在什么地方出现了问题。</p>\n<p>在某些情况下，开发者想要通过组件树直接传递数据，而不是在一层又一层的组件之间手工传递数据。此时，可以使用React的“context”特性接口来快速实现这个功能。</p>\n\n<h2 id="h2-2">尽量不要使用Context</h2>\n<p>React在16.x版本之后算是将Context调整为正式接口，不过还是建议如果组件之间传递数据的层次不算太深，尽量不要使用Context。而且 <a title="redux" href="https://github.com/reactjs/redux"\n                                                                               rel="nofollow">Redux </a>或 <a title="MobX"\n        href="https://github.com/mobxjs/mobx" rel="nofollow">MobX</a>&nbsp;等技术能提供比Context特性更为优雅的实现方式。</p>\n\n<h2 id="h2-3">最新实现方式</h2>\n<p>Context功能在16.x之后所有的API和使用方法都发生了巨大的改变，如果你使用的是最新版本（16.x）看这里最新方式就够了，如果是较早的版本，请看下方的历史实现小节。</p>\n<p>新版本的Context实现方式简洁清晰许多，方式还是以类似于 <a title="高阶组件" href="https://my.oschina.net/chkui/blog/876956" rel="nofollow">高阶组件</a> 包裹的方式为主。\n</p>\n\n<h3 id="h3-1">入门使用案例</h3>\n<p>这是一个没有使用Context特性3个组件组合的使用例子：</p>\n<pre class="scala"><code class="language-javascript"><span class="hljs-class"><span class="code-keyword"><span\n        class="hljs-class"><span class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span\n        class="code-title"><span class="hljs-class"><span class="code-title">App</span></span></span><span\n        class="hljs-class"> </span><span class="code-keyword"><span class="hljs-class"><span class="code-keyword">extends</span></span></span><span\n        class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n        class="code-title">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Component</span></span></span><span\n        class="hljs-class"> </span></span>{\n  render() {\n    <span class="code-keyword"><span class="code-keyword">return</span></span> &lt;<span\n            class="code-type">Toolbar</span> theme=<span class="code-string">"dark"</span> /&gt;;\n  }\n}\n\nfunction <span class="code-type">Toolbar</span>(props) {\n  <span class="code-comment">//为了让子组件能获取必要的参数，这里需要使用props.theme继续向子组件传递参数，</span>\n  <span class="code-comment">//但是实际上theme参数对于Toolbal组件来说并没有任何价值。</span>\n  <span class="code-comment">//例如项目全局设置了一个theme参数来控制很多组件的主题样式，</span>\n  <span class="code-comment">//那么这个参数需要在几乎所有的组件出现，并且不断的传递他</span>\n  <span class="code-keyword">return</span> (\n    &lt;div&gt;\n      &lt;<span class="code-type">ThemedButton</span> theme={props.theme} /&gt;\n    &lt;/div&gt;\n  );\n}\n\nfunction <span class="code-type">ThemedButton</span>(props) {\n  <span class="code-keyword">return</span> &lt;<span class="code-type">Button</span> theme={props.theme} /&gt;;\n}</code></pre>\n<p>上面的theme参数表示全局主题样式，很多组件通过他来控制自己当前应该呈现的样式。如果我们在根组件控制这个参数，那么几乎所有的组件都要向下传递这个参数。</p>\n<p>下面是用Context特性实现的方式：</p>\n<pre class="scala"><code class="language-javascript"><span class="code-comment"><span class="code-comment">// 创建一个Context组件，可以理解为一种特殊的高阶组件。</span></span>\n<span class="code-comment"><span class="code-comment">// \'light\'是当前的默认值</span></span>\n<span class="code-keyword">const</span> <span class="code-type">ThemeContext</span> = <span\n            class="code-type">React</span>.createContext(<span class="code-string"><span\n            class="hljs-symbol">\'ligh</span>t\'</span>);\n\n<span class="hljs-class"><span class="code-keyword"><span class="hljs-class"><span\n        class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">App</span></span></span><span class="hljs-class"> </span><span\n        class="code-keyword"><span class="hljs-class"><span class="code-keyword">extends</span></span></span><span\n        class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n        class="code-title">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Component</span></span></span><span\n        class="hljs-class"> </span></span>{\n  render() {\n    <span class="code-comment"><span class="code-comment">//使用Provider将子组件包裹起来。</span></span>\n    <span class="code-comment"><span class="code-comment">//将值修改为\'dark\'</span></span>\n    <span class="code-keyword"><span class="code-keyword">return</span></span> (\n      &lt;<span class="code-type">ThemeContext</span>.<span class="code-type">Provider</span> value=<span\n            class="code-string">"dark"</span>&gt;\n        &lt;<span class="code-type">Toolbar</span> /&gt;\n      &lt;/<span class="code-type">ThemeContext</span>.<span class="code-type">Provider</span>&gt;\n    );\n  }\n}\n\n<span class="code-comment">//中间组件，并不关心和他无关的参数</span>\nfunction <span class="code-type">Toolbar</span>(props) {\n  <span class="code-keyword">return</span> (\n    &lt;div&gt;\n      &lt;<span class="code-type">ThemedButton</span> /&gt;\n    &lt;/div&gt;\n  );\n}\n\n<span class="code-comment">//使用参数的组件</span>\nfunction <span class="code-type">ThemedButton</span>(props) {\n  <span class="code-comment">// 使用Consumer组件包裹需要获取参数的组件</span>\n  <span class="code-comment">// 在这个案例中，命名为light的Context被赋值"dark"，然后在Consumer中获取这个值</span>\n  <span class="code-keyword">return</span> (\n    &lt;<span class="code-type">ThemeContext</span>.<span class="code-type">Consumer</span>&gt;\n      {theme =&gt; &lt;<span class="code-type">Button</span> {...props} theme={theme} /&gt;}\n    &lt;/<span class="code-type">ThemeContext</span>.<span class="code-type">Consumer</span>&gt;\n  );\n}</code></pre>\n<p>上面就是简单使用Context的例子，16.x之后也是通过高阶组件的方式来实现，是不是看了之后感觉很想Redux。只要是通过 Provider 包裹的组件，在其后的整个组件树中都可以用&nbsp;Consumer\n    来获取指定的数据。</p>\n<p>上面的代码我们也可以修改为下面这样更直观的形式：</p>\n<pre class="javascript"><code class="language-javascript"><span class="code-keyword"><span\n        class="code-keyword">const</span></span> {Provider, Consumer} = React.createContext(<span\n        class="code-string"><span class="code-string">\'light\'</span></span>);\n<span class="hljs-class"><span class="code-keyword"><span class="hljs-class"><span\n        class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">App</span></span></span><span class="hljs-class"> </span><span\n        class="code-keyword"><span class="hljs-class"><span class="code-keyword">extends</span></span></span><span\n        class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n        class="code-title">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Component</span></span></span><span\n        class="hljs-class"> </span></span>{\n  render() {\n    <span class="code-keyword"><span class="code-keyword">return</span></span> (\n      <span class="xml"><span class="code-tag"><span class="xml"><span class="code-tag">&lt;</span></span><span\n              class="code-name"><span class="xml"><span class="code-tag"><span class="code-name">Provider</span></span></span></span><span\n              class="xml"><span class="code-tag"> </span></span><span class="hljs-attr"><span class="xml"><span\n              class="code-tag"><span class="hljs-attr">value</span></span></span></span><span class="xml"><span\n              class="code-tag">=</span></span><span class="code-string"><span class="xml"><span class="code-tag"><span\n              class="code-string">"dark"</span></span></span></span><span class="xml"><span class="code-tag">&gt;</span></span></span><span\n              class="xml">\n        </span><span class="code-tag"><span class="xml"><span class="code-tag">&lt;</span></span><span\n              class="code-name"><span class="xml"><span class="code-tag"><span\n              class="code-name">Toolbar</span></span></span></span><span class="xml"><span\n              class="code-tag"> /&gt;</span></span></span><span class="xml">\n      </span><span class="code-tag"><span class="xml"><span class="code-tag">&lt;/</span></span><span class="code-name"><span\n              class="xml"><span class="code-tag"><span class="code-name">Provider</span></span></span></span><span\n              class="xml"><span class="code-tag">&gt;</span></span></span></span>\n    );\n  }\n}\n<span class="hljs-function"><span class="code-keyword"><span class="hljs-function"><span\n        class="code-keyword">function</span></span></span><span class="hljs-function"> </span><span\n        class="code-title"><span class="hljs-function"><span class="code-title">Toolbar</span></span></span><span\n        class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">props</span></span></span><span\n        class="hljs-function">) </span></span>{\n  <span class="code-keyword"><span class="code-keyword">return</span></span> (\n    <span class="xml"><span class="code-tag"><span class="xml"><span class="code-tag">&lt;</span></span><span\n            class="code-name"><span class="xml"><span class="code-tag"><span class="code-name">div</span></span></span></span><span\n            class="xml"><span class="code-tag">&gt;</span></span></span><span class="xml">\n      </span><span class="code-tag"><span class="xml"><span class="code-tag">&lt;</span></span><span\n            class="code-name"><span class="xml"><span class="code-tag"><span\n            class="code-name">ThemedButton</span></span></span></span><span class="xml"><span\n            class="code-tag"> /&gt;</span></span></span><span class="xml">\n    </span><span class="code-tag"><span class="xml"><span class="code-tag">&lt;/</span></span><span\n            class="code-name"><span class="xml"><span class="code-tag"><span class="code-name">div</span></span></span></span><span\n            class="xml"><span class="code-tag">&gt;</span></span></span></span>\n  );\n}\n<span class="hljs-function"><span class="code-keyword"><span class="hljs-function"><span\n        class="code-keyword">function</span></span></span><span class="hljs-function"> </span><span\n        class="code-title"><span class="hljs-function"><span class="code-title">ThemedButton</span></span></span><span\n        class="hljs-function">(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">props</span></span></span><span\n        class="hljs-function">) </span></span>{\n  <span class="code-keyword"><span class="code-keyword">return</span></span> (\n    <span class="xml"><span class="code-tag"><span class="xml"><span class="code-tag">&lt;</span></span><span\n            class="code-name"><span class="xml"><span class="code-tag"><span\n            class="code-name">Consumer</span></span></span></span><span class="xml"><span\n            class="code-tag">&gt;</span></span></span><span class="xml">\n      {theme =&gt; </span><span class="code-tag"><span class="xml"><span class="code-tag">&lt;</span></span><span\n            class="code-name"><span class="xml"><span class="code-tag"><span\n            class="code-name">Button</span></span></span></span><span class="xml"><span\n            class="code-tag"> {</span></span><span class="hljs-attr"><span class="xml"><span class="code-tag"><span\n            class="hljs-attr">...props</span></span></span></span><span class="xml"><span\n            class="code-tag">} </span></span><span class="hljs-attr"><span class="xml"><span class="code-tag"><span\n            class="hljs-attr">theme</span></span></span></span><span class="xml"><span\n            class="code-tag">=</span></span><span class="code-string"><span class="xml"><span class="code-tag"><span\n            class="code-string">{theme}</span></span></span></span><span class="xml"><span\n            class="code-tag"> /&gt;</span></span></span><span class="xml">}\n    </span><span class="code-tag"><span class="xml"><span class="code-tag">&lt;/</span></span><span\n            class="code-name"><span class="xml"><span class="code-tag"><span\n            class="code-name">Consumer</span></span></span></span><span class="xml"><span\n            class="code-tag">&gt;</span></span></span><span class="xml">\n  );\n}</span></span></code></pre>\n<p>使用Context需要注意：</p>\n<ol>\n    <li>由于&nbsp;Provider 和&nbsp;Consumer都是返回一个组件，所以我们最好设定一个默认的context.value，以防止出现渲染错误。</li>\n    <li>当Provider发生数据变更时，会触发到 Consumer 发生渲染，所有被其包裹的子组件都会发生渲染（render方法被调用）。</li>\n</ol>\n\n<h3 id="h3-2">任意组件更新Context</h3>\n<p>某些时候需要在内部组件需要去更新Context的数据，其实我们仅仅需要向上下文增加一个回调即可，看下面的例子：</p>\n<pre class="scala"><code class="language-javascript"><span class="code-comment"><span\n        class="code-comment">//创建Context组件</span></span>\n<span class="code-keyword">const</span> <span class="code-type">ThemeContext</span> = <span\n            class="code-type">React</span>.createContext({\n  theme: <span class="code-string"><span class="hljs-symbol">\'dar</span>k\'</span>,\n  toggle: () =&gt; {}, <span class="code-comment"><span class="code-comment">//向上下文设定一个回调方法</span></span>\n});\n\n<span class="hljs-function"><span class="code-keyword">function</span> <span class="code-title"><span class="code-type">Button</span></span>(<span\n        class="hljs-params"></span>) </span>{\n  <span class="code-keyword"><span class="code-keyword">return</span></span> (\n    &lt;<span class="code-type">ThemeContext</span>.<span class="code-type">Consumer</span>&gt;\n      {({theme, toggle}) =&gt; (\n        &lt;button\n          onClick={toggle} <span class="code-comment">//调用回调</span>\n          style={{backgroundColor: theme}}&gt;\n          <span class="code-type">Toggle</span> <span class="code-type">Theme</span>\n        &lt;/button&gt;\n      )}\n    &lt;/<span class="code-type">ThemeContext</span>.<span class="code-type">Consumer</span>&gt;\n  );\n}\n\n<span class="code-comment">//中间组件</span>\nfunction <span class="code-type">Content</span>() {\n  <span class="code-keyword">return</span> (\n    &lt;div&gt;\n      &lt;<span class="code-type">Button</span> /&gt;\n    &lt;/div&gt;\n  );\n}\n\n<span class="code-comment">//运行APP</span>\n<span class="hljs-class"><span class="code-keyword">class</span> <span class="code-title">App</span> <span\n        class="code-keyword">extends</span> <span class="code-title">React</span>.<span\n        class="code-title">Component</span> </span>{\n  constructor(props) {\n    <span class="code-keyword">super</span>(props);\n\n    <span class="code-keyword">this</span>.toggle = () =&gt; { <span\n            class="code-comment">//设定toggle方法，会作为context参数传递</span>\n      <span class="code-keyword">this</span>.setState(state =&gt; ({\n        theme:\n          state.theme === themes.dark\n            ? themes.light\n            : themes.dark,\n      }));\n    };\n\n    <span class="code-keyword">this</span>.state = {\n      theme: themes.light,\n      toggle: <span class="code-keyword">this</span>.toggle,\n    };\n  }\n\n  render() {\n    <span class="code-keyword">return</span> (\n      &lt;<span class="code-type">ThemeContext</span>.<span class="code-type">Provider</span> value={<span\n            class="code-keyword">this</span>.state}&gt; <span class="code-comment">//state包含了toggle方法</span>\n        &lt;<span class="code-type">Content</span> /&gt;\n      &lt;/<span class="code-type">ThemeContext</span>.<span class="code-type">Provider</span>&gt;\n    );\n  }\n}</code></pre>\n<p>App组件创建了Provider，并向其参数传递了一个回调方法，之后任何使用了 Consumer 的子孙组件都可以使用这个回调方法了触发更新。</p>\n\n<h3 id="h3-3">多个Context复合使用</h3>\n<p>React支持设置多个Context，看下面的例子：</p>\n<pre class="haskell"><code class="language-javascript"><span class="code-keyword"><span class="code-title">const</span></span> <span\n        class="code-type">ThemeContext</span> = <span class="code-type">React</span>.createContext(<span\n        class="code-string">\'light\'</span>)，\n       <span class="code-type">UserContext</span> = <span class="code-type">React</span>.createContext({\n           name: <span class="code-string">\'<span class="code-type">Guest\'</span></span>,\n       });\n<span class="hljs-class">\n</span><span class="hljs-class"><span class="code-keyword"><span class="hljs-class"><span\n            class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span\n            class="code-title"><span class="hljs-class"><span class="code-type">App</span></span></span><span\n            class="hljs-class"> </span><span class="code-keyword"><span class="hljs-class">extends</span></span><span\n            class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n            class="code-type">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n            class="hljs-class"><span class="code-type">Component</span></span></span><span\n            class="hljs-class"> </span></span><span class="hljs-class">{\n  render() {\n    </span><span class="code-keyword"><span class="hljs-class">const</span></span><span class="hljs-class"> {signedInUser, theme} = </span><span\n            class="code-keyword"><span class="hljs-class">this</span></span><span class="hljs-class">.props;\n    </span><span class="code-keyword"><span class="hljs-class">return</span></span><span class="hljs-class"> (\n      &lt;<span class="code-type">ThemeContext</span>.<span class="code-type">Provider</span> <span class="code-title">value</span>={<span\n                class="code-title">theme</span>}&gt;\n        &lt;<span class="code-type">UserContext</span>.<span class="code-type">Provider</span> <span class="code-title">value</span>={<span\n                class="code-title">signedInUser</span>}&gt;\n          &lt;<span class="code-type">Layout</span> /&gt;\n        &lt;/<span class="code-type">UserContext</span>.<span class="code-type">Provider</span>&gt;\n      &lt;/<span class="code-type">ThemeContext</span>.<span class="code-type">Provider</span>&gt;\n    );\n  }\n}\n\nfunction <span class="code-type">Layout</span>() {\n  return (\n    &lt;<span class="code-title">div</span>&gt;\n      &lt;<span class="code-type">Sidebar</span> /&gt;\n      &lt;<span class="code-type">Content</span> /&gt;\n    &lt;/<span class="code-title">div</span>&gt;\n  );\n}\n\nfunction <span class="code-type">Content</span>() {\n  return (\n    &lt;<span class="code-type">ThemeContext</span>.<span class="code-type">Consumer</span>&gt;\n      {<span class="code-title">theme</span> =&gt; (\n        &lt;<span class="code-type">UserContext</span>.<span class="code-type">Consumer</span>&gt;\n          {<span class="code-title">user</span> =&gt; (\n            &lt;<span class="code-type">ProfilePage</span> <span class="code-title">user</span>={<span\n                class="code-title">user</span>} <span class="code-title">theme</span>={<span\n                class="code-title">theme</span>} /&gt;\n          )}\n        &lt;/<span class="code-type">UserContext</span>.<span class="code-type">Consumer</span>&gt;\n      )}\n    &lt;/<span class="code-type">ThemeContext</span>.<span class="code-type">Consumer</span>&gt;\n  );\n}</span></code></pre>\n<p>和使用单个Context也没多大区别，相互包装一层即可。</p>\n<p>使用Context时需要牢记一点：和Redux一样，只要 <strong><em>Provider </em></strong>的value发生变更都会触发所有 <strong><em>Consumer</em></strong>\n    包裹的子组件渲染。</p>\n<p>16.x之后的Context使用起来比旧版本的简单明了太多，实现思路上还是学习了Redux等将状态抽取出来统一管理并触发更新的方式来实现，在使用时选择一种方式来实现就行。</p>\n\n<h2 id="h2-4">历史实现</h2>\n\n<h4 id="h4-1">如何使用Context</h4>\n<p>假设有下面这样一个组件结构：</p>\n<pre class="scala"><code class="language-javascript"><span class="hljs-class"><span class="code-keyword"><span\n        class="hljs-class"><span class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span\n        class="code-title"><span class="hljs-class"><span class="code-title">Button</span></span></span><span\n        class="hljs-class"> </span><span class="code-keyword"><span class="hljs-class"><span class="code-keyword">extends</span></span></span><span\n        class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n        class="code-title">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Component</span></span></span><span\n        class="hljs-class"> </span></span>{\n  render() {\n    <span class="code-keyword"><span class="code-keyword">return</span></span> (\n      <span class="xml"><span class="code-tag">&lt;<span class="code-name">button</span> <span\n              class="hljs-attr">style</span>=<span class="code-string">{{background:</span> <span\n              class="hljs-attr"><span class="code-keyword">this</span>.props.color</span>}}&gt;</span>\n        {<span class="code-keyword">this</span>.props.children}\n      <span class="code-tag">&lt;/<span class="code-name">button</span>&gt;</span></span>\n    );\n  }\n}\n\n<span class="hljs-class"><span class="code-keyword"><span class="hljs-class"><span\n        class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Message</span></span></span><span class="hljs-class"> </span><span\n        class="code-keyword"><span class="hljs-class"><span class="code-keyword">extends</span></span></span><span\n        class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n        class="code-title">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Component</span></span></span><span\n        class="hljs-class"> </span></span>{\n  render() {\n    <span class="code-keyword"><span class="code-keyword">return</span></span> (\n      <span class="xml"><span class="code-tag">&lt;<span class="code-name">div</span>&gt;</span>\n        {<span class="code-keyword">this</span>.props.text} <span class="code-tag">&lt;<span class="code-name"><span\n                  class="code-type">Button</span></span> <span class="hljs-attr">color</span>=<span class="code-string">{<span\n                  class="code-keyword">this</span>.props.color}</span>&gt;</span><span\n                  class="code-type">Delete</span><span class="code-tag">&lt;/<span class="code-name"><span\n                  class="code-type">Button</span></span>&gt;</span>\n      <span class="code-tag">&lt;/<span class="code-name">div</span>&gt;</span></span>\n    );\n  }\n}\n\n<span class="hljs-class"><span class="code-keyword"><span class="hljs-class"><span\n        class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">MessageList</span></span></span><span\n        class="hljs-class"> </span><span class="code-keyword"><span class="hljs-class"><span class="code-keyword">extends</span></span></span><span\n        class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n        class="code-title">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Component</span></span></span><span\n        class="hljs-class"> </span></span>{\n  render() {\n    <span class="code-keyword">const</span> color = <span class="code-string"><span class="code-string">"purple"</span></span>;\n    <span class="code-keyword">const</span> children = <span class="code-keyword"><span class="code-keyword">this</span></span>.props.messages.map((message) =&gt;\n      <span class="xml"><span class="code-tag">&lt;<span class="code-name"><span class="code-type">Message</span></span> <span\n              class="hljs-attr">text</span>=<span class="code-string">{message.text}</span> <span class="hljs-attr">color</span>=<span\n              class="code-string">{color}</span> /&gt;</span>\n    );\n    <span class="code-keyword">return</span> <span class="code-tag">&lt;<span class="code-name">div</span>&gt;</span>{children}<span\n                  class="code-tag">&lt;/<span class="code-name">div</span>&gt;</span>;\n  }\n}</span></code></pre>\n<p>在上面的例子中，在最外层组件手工传入一个<code>color</code>属性参数来指定<code>Button</code>组件的颜色。如果使用Context特性，我们可以直接将属性自动的传递给整个组件树：</p>\n<pre class="scala"><code class="language-javascript"><span class="code-keyword">const</span> <span class="code-type">PropTypes</span> = <span\n        class="code-built_in">require</span>(<span class="code-string"><span\n        class="hljs-symbol">\'prop</span>-types\'</span>);\n\n<span class="hljs-class"><span class="code-keyword"><span class="hljs-class"><span\n        class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Button</span></span></span><span class="hljs-class"> </span><span\n        class="code-keyword"><span class="hljs-class"><span class="code-keyword">extends</span></span></span><span\n        class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n        class="code-title">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Component</span></span></span><span\n        class="hljs-class"> </span></span>{\n  render() {\n    <span class="code-comment"><span class="code-comment">// 注意this.context.color</span></span>\n    <span class="code-keyword"><span class="code-keyword">return</span></span> (\n      <span class="xml"><span class="code-tag">&lt;<span class="code-name">button</span> <span\n              class="hljs-attr">style</span>=<span class="code-string">{{background:</span> <span\n              class="hljs-attr"><span class="code-keyword">this</span>.context.color</span>}}&gt;</span>\n        {<span class="code-keyword">this</span>.props.children}\n      <span class="code-tag">&lt;/<span class="code-name">button</span>&gt;</span></span>\n    );\n  }\n}\n\n<span class="code-comment"><span class="code-comment">// 限定color属性只接收string类型的参数</span></span>\n<span class="code-type">Button</span>.contextTypes = {\n  color: <span class="code-type">PropTypes</span>.string\n};\n\n<span class="hljs-class"><span class="code-keyword"><span class="hljs-class"><span\n        class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Message</span></span></span><span class="hljs-class"> </span><span\n        class="code-keyword"><span class="hljs-class"><span class="code-keyword">extends</span></span></span><span\n        class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n        class="code-title">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Component</span></span></span><span\n        class="hljs-class"> </span></span>{\n  render() {\n    <span class="code-keyword"><span class="code-keyword">return</span></span> (\n      <span class="xml"><span class="code-tag">&lt;<span class="code-name">div</span>&gt;</span>\n        {<span class="code-keyword">this</span>.props.text} <span class="code-tag">&lt;<span class="code-name"><span\n                  class="code-type">Button</span></span>&gt;</span><span class="code-type">Delete</span><span\n                  class="code-tag">&lt;/<span class="code-name"><span class="code-type">Button</span></span>&gt;</span>\n      <span class="code-tag">&lt;/<span class="code-name">div</span>&gt;</span></span>\n    );\n  }\n}\n\n<span class="hljs-class"><span class="code-keyword"><span class="hljs-class"><span\n        class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">MessageList</span></span></span><span\n        class="hljs-class"> </span><span class="code-keyword"><span class="hljs-class"><span class="code-keyword">extends</span></span></span><span\n        class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n        class="code-title">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Component</span></span></span><span\n        class="hljs-class"> </span></span>{\n  <span class="code-comment"><span class="code-comment">// 在后续组件中设定一个Context的值</span></span>\n  getChildContext() {\n    <span class="code-keyword"><span class="code-keyword">return</span></span> {color: <span class="code-string"><span\n            class="code-string">"purple"</span></span>};\n  }\n\n  render() {\n    <span class="code-keyword">const</span> children = <span class="code-keyword"><span class="code-keyword">this</span></span>.props.messages.map((message) =&gt;\n      <span class="xml"><span class="code-tag">&lt;<span class="code-name"><span class="code-type">Message</span></span> <span\n              class="hljs-attr">text</span>=<span class="code-string">{message.text}</span> /&gt;</span>\n    );\n    <span class="code-keyword">return</span> <span class="code-tag">&lt;<span class="code-name">div</span>&gt;</span>{children}<span\n                  class="code-tag">&lt;/<span class="code-name">div</span>&gt;</span>;\n  }\n}\n\n<span class="code-comment">//限定子组件的color值只接收string类型的参数</span>\n<span class="code-type">MessageList</span>.childContextTypes = {\n  color: <span class="code-type">PropTypes</span>.string\n};</span></code></pre>\n<p>\n    通过在&nbsp;<code>MessageList</code>&nbsp;组件（Context的制定者）中增加&nbsp;&nbsp;<code>childContextTypes</code>&nbsp;和&nbsp;<code>getChildContext</code>&nbsp;，React会自动将这个指定的context值传递到所有子组件中（比如例子中的&nbsp;<code>Button</code>组件），而子组件也可以定义一个&nbsp;<code>contextTypes</code>&nbsp;来指定接收context的内容。如果未定义子组件的&nbsp;<code>contextTypes</code>&nbsp;，那么调用&nbsp;&nbsp;<code>context</code>&nbsp;只能得到一个空对象。\n</p>\n\n<h4 id="h4-2">父子组件耦合</h4>\n<p>Context特性还可以让开发人员快速构建父组件与子组件之间的联系。例如在&nbsp;<a href="https://reacttraining.com/react-router" rel="nofollow">React\n    Router V4</a>&nbsp;包中：</p>\n<pre class="dust"><code class="language-javascript"><span class="code-keyword"><span\n        class="xml">import</span></span><span class="xml"> </span><span\n        class="code-template-variable">{ BrowserRouter </span><span class="code-keyword"><span\n        class="code-template-variable">as</span></span><span\n        class="code-template-variable"> Router, Route, Link }</span><span class="xml"> </span><span\n        class="code-keyword"><span class="xml">from</span></span><span class="xml"> </span><span\n        class="code-string"><span class="xml">\'react-router-dom\'</span></span><span class="xml">;\n\n</span><span class="code-keyword"><span class="xml">const</span></span><span class="xml"> BasicExample = () =&gt; (\n  <span class="code-tag">&lt;<span class="code-name">Router</span>&gt;</span>\n    <span class="code-tag">&lt;<span class="code-name">div</span>&gt;</span>\n      <span class="code-tag">&lt;<span class="code-name">ul</span>&gt;</span>\n        <span class="code-tag">&lt;<span class="code-name">li</span>&gt;</span><span class="code-tag">&lt;<span\n            class="code-name">Link</span> <span class="hljs-attr">to</span>=<span\n            class="code-string">"/"</span>&gt;</span>Home<span class="code-tag">&lt;/<span class="code-name">Link</span>&gt;</span><span\n            class="code-tag">&lt;/<span class="code-name">li</span>&gt;</span>\n        <span class="code-tag">&lt;<span class="code-name">li</span>&gt;</span><span class="code-tag">&lt;<span\n            class="code-name">Link</span> <span class="hljs-attr">to</span>=<span class="code-string">"/about"</span>&gt;</span>About<span\n            class="code-tag">&lt;/<span class="code-name">Link</span>&gt;</span><span class="code-tag">&lt;/<span\n            class="code-name">li</span>&gt;</span>\n        <span class="code-tag">&lt;<span class="code-name">li</span>&gt;</span><span class="code-tag">&lt;<span\n            class="code-name">Link</span> <span class="hljs-attr">to</span>=<span class="code-string">"/topics"</span>&gt;</span>Topics<span\n            class="code-tag">&lt;/<span class="code-name">Link</span>&gt;</span><span class="code-tag">&lt;/<span\n            class="code-name">li</span>&gt;</span>\n      <span class="code-tag">&lt;/<span class="code-name">ul</span>&gt;</span>\n\n      <span class="code-tag">&lt;<span class="code-name">hr</span> /&gt;</span>\n\n      <span class="code-tag">&lt;<span class="code-name">Route</span> <span class="hljs-attr">exact</span> <span\n              class="hljs-attr">path</span>=<span class="code-string">"/"</span> <span\n              class="hljs-attr">component</span>=</span></span><span class="code-template-variable">{Home}</span><span\n        class="xml"><span class="code-tag"> /&gt;</span>\n      <span class="code-tag">&lt;<span class="code-name">Route</span> <span class="hljs-attr">path</span>=<span\n              class="code-string">"/about"</span> <span class="hljs-attr">component</span>=</span></span><span\n        class="code-template-variable">{About}</span><span class="xml"><span class="code-tag"> /&gt;</span>\n      <span class="code-tag">&lt;<span class="code-name">Route</span> <span class="hljs-attr">path</span>=<span\n              class="code-string">"/topics"</span> <span class="hljs-attr">component</span>=</span></span><span\n        class="code-template-variable">{Topics}</span><span class="xml"><span class="code-tag"> /&gt;</span>\n    <span class="code-tag">&lt;/<span class="code-name">div</span>&gt;</span>\n  <span class="code-tag">&lt;/<span class="code-name">Router</span>&gt;</span>\n);</span></code></pre>\n<p>例子通过Router组件传递一些数据，每一个被<code>Router</code>包含的&nbsp;<code>Link</code>&nbsp;和&nbsp;<code>Route</code>&nbsp;都可以直接通信。但是建议在使用这些API构建组件时，先思考是否还有其他更清晰的实现方式。例如可以使用回调的方式去组合组件。\n</p>\n\n<h4 id="h4-3">在生命周期方法中引入Context</h4>\n<p>如果在某个组件上定义了&nbsp;<code>contextTypes</code>&nbsp;，下面这些生命周期方法将会接收到额外的参数—— &nbsp;<code>context</code>&nbsp;对象。我们这里这样调整参数接口：\n</p>\n<ul>\n    <li><a href="https://facebook.github.io/react/docs/react-component.html#constructor" rel="nofollow"><code>constructor(props,\n        context)</code></a></li>\n    <li><a href="https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops"\n           rel="nofollow"><code>componentWillReceiveProps(nextProps, nextContext)</code></a></li>\n    <li><a href="https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate" rel="nofollow"><code>shouldComponentUpdate(nextProps,\n        nextState, nextContext)</code></a></li>\n    <li><a href="https://facebook.github.io/react/docs/react-component.html#componentwillupdate" rel="nofollow"><code>componentWillUpdate(nextProps,\n        nextState, nextContext)</code></a></li>\n    <li><a href="https://facebook.github.io/react/docs/react-component.html#componentdidupdate" rel="nofollow"><code>componentDidUpdate(prevProps,\n        prevState, prevContext)</code></a></li>\n</ul>\n\n<h4 id="h4-4">在无状态的方法性组件中引入Context</h4>\n<p>无状态的方法性组件也可以引入Context，前提是给组件定义了&nbsp;<code>contextTypes</code>&nbsp;。下面的代码展示了在无状态的组件——&nbsp;<code>Button</code>&nbsp;中引入context的表达式：\n</p>\n<pre class="javascript"><code class="language-javascript"><span class="code-keyword"><span\n        class="code-keyword">const</span></span> PropTypes = <span class="code-built_in"><span class="code-built_in">require</span></span>(<span\n        class="code-string"><span class="code-string">\'prop-types\'</span></span>);\n\n<span class="code-keyword"><span class="code-keyword">const</span></span> Button = ({children}, context) =&gt;\n  <span class="xml"><span class="code-tag"><span class="xml"><span class="code-tag">&lt;</span></span><span\n          class="code-name"><span class="xml"><span class="code-tag"><span class="code-name">button</span></span></span></span><span\n          class="xml"><span class="code-tag"> </span></span><span class="hljs-attr"><span class="xml"><span\n          class="code-tag"><span class="hljs-attr">style</span></span></span></span><span class="xml"><span\n          class="code-tag">=</span></span><span class="code-string"><span class="xml"><span class="code-tag"><span\n          class="code-string">{{background:</span></span></span></span><span class="xml"><span class="code-tag"> </span></span><span\n          class="hljs-attr"><span class="xml"><span class="code-tag"><span class="hljs-attr">context.color</span></span></span></span><span\n          class="xml"><span class="code-tag">}}&gt;</span></span></span><span class="xml">\n    {children}\n  </span><span class="code-tag"><span class="xml"><span class="code-tag">&lt;/</span></span><span\n          class="code-name"><span class="xml"><span class="code-tag"><span class="code-name">button</span></span></span></span><span\n          class="xml"><span class="code-tag">&gt;</span></span></span></span>;\n\nButton.contextTypes = {color: PropTypes.string};</code></pre>\n\n<h4 id="h4-5">更新Context</h4>\n<p>首先，千万不要更新Context。</p>\n<p>React提供一个更新Context的接口，但是它会从根本上破坏React的结构所以建议不要使用他。</p>\n<p><code>getChildContext</code>&nbsp;在state或props变更时会被调用。为了更新context中的数据可以使用&nbsp;<code>this.setState</code>方法来触发变更，触发之后context的更新会被子组件接收到。\n</p>\n<pre class="scala"><code class="language-javascript"><span class="code-keyword">const</span> <span class="code-type">PropTypes</span> = <span\n        class="code-built_in">require</span>(<span class="code-string"><span\n        class="hljs-symbol">\'prop</span>-types\'</span>);\n\n<span class="hljs-class"><span class="code-keyword"><span class="hljs-class"><span\n        class="code-keyword">class</span></span></span><span class="hljs-class"> </span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">MediaQuery</span></span></span><span\n        class="hljs-class"> </span><span class="code-keyword"><span class="hljs-class"><span class="code-keyword">extends</span></span></span><span\n        class="hljs-class"> </span><span class="code-title"><span class="hljs-class"><span\n        class="code-title">React</span></span></span><span class="hljs-class">.</span><span class="code-title"><span\n        class="hljs-class"><span class="code-title">Component</span></span></span><span\n        class="hljs-class"> </span></span>{\n  <span class="code-keyword">constructor</span>(props) {\n    <span class="code-keyword"><span class="code-keyword">super</span></span>(props);\n    <span class="code-keyword"><span class="code-keyword">this</span></span>.state = {<span class="hljs-class"><span\n            class="code-keyword">type</span></span>:<span class="code-string"><span class="hljs-symbol">\'deskto</span>p\'</span>};\n  }\n\n  getChildContext() {\n    <span class="code-keyword"><span class="code-keyword">return</span></span> {<span class="hljs-class"><span\n            class="code-keyword">type</span></span>: <span class="code-keyword"><span\n            class="code-keyword">this</span></span>.state.<span class="code-keyword">type</span>};\n  }\n\n  componentDidMount() {\n    <span class="code-keyword">const</span> checkMediaQuery = () =&gt; {\n      <span class="code-keyword">const</span> <span class="hljs-class"><span\n            class="code-keyword">type</span> </span>= <span class="code-built_in">window</span>.matchMedia(<span\n            class="code-string"><span class="code-string">"(min-width: 1025px)"</span></span>).matches ? <span\n            class="code-string"><span class="hljs-symbol">\'deskto</span>p\'</span> : <span class="code-string"><span\n            class="hljs-symbol">\'mobil</span>e\'</span>;\n      <span class="code-keyword"><span class="code-keyword">if</span></span> (<span class="hljs-class"><span\n            class="code-keyword">type</span> <span class="code-title">!==</span> </span><span class="code-keyword"><span\n            class="hljs-class"><span class="code-title">this</span></span></span><span class="hljs-class">.<span\n            class="code-title">state</span>.<span class="code-title">type</span>) </span>{\n        <span class="code-keyword"><span class="code-keyword">this</span></span>.setState({<span\n            class="hljs-class"><span class="code-keyword">type</span>})</span>;\n      }\n    };\n\n    <span class="code-built_in">window</span>.addEventListener(<span class="code-string"><span class="hljs-symbol">\'resiz</span>e\'</span>, checkMediaQuery);\n    checkMediaQuery();\n  }\n\n  render() {\n    <span class="code-keyword"><span class="code-keyword">return</span></span> <span class="code-keyword"><span\n            class="code-keyword">this</span></span>.props.children;\n  }\n}\n<span class="code-type">MediaQuery</span>.childContextTypes = {\n  <span class="hljs-class"><span class="code-keyword">type</span></span>: <span class="code-type">PropTypes</span>.string\n};</code></pre>\n<p>这里的问题在于，如果一个context在组件变更时才产生，接下来如果中间某个组件的&nbsp;<code>shouldComponentUpdate</code>方法返回fasle值，那么后续组件无法从context中得到任何值。所以，如果使用context来维护管理状态，那么就需要从全局去控制组件，这和React单向数据流和组件化的思路有些背道而驰。而且随着应用的扩展以及人员的更变，全局管理状态会越来越难。如果你还想了解更多关于context的问题，可以阅读这篇博客文章——“<a\n        href="https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076" rel="nofollow">How To Safely\n    Use React Context</a>"（翻墙），里面讨论了如果绕开这些问题。</p>'}};