<p dir="auto">We accidentally applied PureRenderMixin to a page that that rendered the same result given the same props and state, however, it broke the page since the context changed (for a isUserLoggedIn).</p>
<p dir="auto">I know <code class="notranslate">this.context</code> is not officially there but quite a few libraries rely on it, and it seems like it's getting into shape with <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="48577524" data-permission-text="Title is private" data-url="https://github.com/facebook/react/issues/2509" data-hovercard-type="pull_request" data-hovercard-url="/facebook/react/pull/2509/hovercard" href="https://github.com/facebook/react/pull/2509">#2509</a>.</p>
<p dir="auto">I'm trying to understand how exactly <code class="notranslate">shouldComponentUpdate</code> is supposed to be implemented with <code class="notranslate">context</code> in mind. I noticed it accepts a third argument (<code class="notranslate">nextContext</code>) and I can extend <code class="notranslate">PureRenderMixin</code> to also check it:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="  shouldComponentUpdate: function(nextProps, nextState, nextContext) {
    return !shallowEqual(this.props, nextProps) ||
           !shallowEqual(this.state, nextState) ||
           !shallowEqual(this.context, nextContext); // this will throw without context, read on
  }"><pre class="notranslate">  shouldComponentUpdate: <span class="pl-k">function</span><span class="pl-kos">(</span><span class="pl-s1">nextProps</span><span class="pl-kos">,</span> <span class="pl-s1">nextState</span><span class="pl-kos">,</span> <span class="pl-s1">nextContext</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-c1">!</span><span class="pl-en">shallowEqual</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">props</span><span class="pl-kos">,</span> <span class="pl-s1">nextProps</span><span class="pl-kos">)</span> <span class="pl-c1">||</span>
           <span class="pl-c1">!</span><span class="pl-en">shallowEqual</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">state</span><span class="pl-kos">,</span> <span class="pl-s1">nextState</span><span class="pl-kos">)</span> <span class="pl-c1">||</span>
           <span class="pl-c1">!</span><span class="pl-en">shallowEqual</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">context</span><span class="pl-kos">,</span> <span class="pl-s1">nextContext</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// this will throw without context, read on</span>
  <span class="pl-kos">}</span></pre></div>
<p dir="auto">Components that don't opt into <code class="notranslate">this.context</code> by not omitting <code class="notranslate">contextTypes</code> will not get this third argument, which is understandable.</p>
<p dir="auto">However this presents a problem when we have a <code class="notranslate">&lt;Middle /&gt;</code> component in between between <code class="notranslate">&lt;Top /&gt;</code> context owner and <code class="notranslate">&lt;Bottom /&gt;</code> context consumer. If <code class="notranslate">&lt;Middle /&gt;</code> implements a restrictive <code class="notranslate">shouldComponentUpdate</code>, there is no way for <code class="notranslate">&lt;Bottom /&gt;</code> to react to <code class="notranslate">&lt;Top /&gt;</code>'s context updates at all:</p>
<p dir="auto">(<strong><a href="http://jsbin.com/radakepusi/2/edit?js,output" rel="nofollow">fiddle</a></strong>)</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="var Bottom = React.createClass({
  contextTypes: {
    number: React.PropTypes.number.isRequired
  },

  render: function () {
    return &lt;h1&gt;{this.context.number}&lt;/h1&gt;
  }
});

var Middle = React.createClass({
  shouldComponentUpdate: function (nextProps, nextState, nextContext) {
    return false;
  },

  render: function () {
    return &lt;Bottom /&gt;;
  }
});

var Top = React.createClass({
  childContextTypes: {
    number: React.PropTypes.number.isRequired
  },

  getInitialState: function () {
    return { number: 0 };
  },

  getChildContext: function () {
    return { number: this.state.number };
  },

  componentDidMount: function () {
    setInterval(function () {
      this.setState({
        number: this.state.number + 1
      });
    }.bind(this), 1000);
  },

  render: function() {
    return &lt;Middle /&gt;;    
  }
});

React.render(&lt;Top /&gt;, document.body);"><pre class="notranslate"><span class="pl-k">var</span> <span class="pl-v">Bottom</span> <span class="pl-c1">=</span> <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-en">createClass</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
  <span class="pl-c1">contextTypes</span>: <span class="pl-kos">{</span>
    <span class="pl-c1">number</span>: <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-c1">PropTypes</span><span class="pl-kos">.</span><span class="pl-c1">number</span><span class="pl-kos">.</span><span class="pl-c1">isRequired</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>

  <span class="pl-en">render</span>: <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-c1">&lt;</span><span class="pl-ent">h1</span><span class="pl-c1">&gt;</span><span class="pl-kos">{</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">context</span><span class="pl-kos">.</span><span class="pl-c1">number</span><span class="pl-kos">}</span><span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">h1</span><span class="pl-c1">&gt;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-k">var</span> <span class="pl-v">Middle</span> <span class="pl-c1">=</span> <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-en">createClass</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
  <span class="pl-en">shouldComponentUpdate</span>: <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-s1">nextProps</span><span class="pl-kos">,</span> <span class="pl-s1">nextState</span><span class="pl-kos">,</span> <span class="pl-s1">nextContext</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-c1">false</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>

  <span class="pl-en">render</span>: <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-c1">&lt;</span><span class="pl-v">Bottom</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-k">var</span> <span class="pl-v">Top</span> <span class="pl-c1">=</span> <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-en">createClass</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
  <span class="pl-c1">childContextTypes</span>: <span class="pl-kos">{</span>
    <span class="pl-c1">number</span>: <span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-c1">PropTypes</span><span class="pl-kos">.</span><span class="pl-c1">number</span><span class="pl-kos">.</span><span class="pl-c1">isRequired</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>

  <span class="pl-en">getInitialState</span>: <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-kos">{</span> <span class="pl-c1">number</span>: <span class="pl-c1">0</span> <span class="pl-kos">}</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>

  <span class="pl-en">getChildContext</span>: <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-kos">{</span> <span class="pl-c1">number</span>: <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">state</span><span class="pl-kos">.</span><span class="pl-c1">number</span> <span class="pl-kos">}</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>

  <span class="pl-en">componentDidMount</span>: <span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-en">setInterval</span><span class="pl-kos">(</span><span class="pl-k">function</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
      <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-en">setState</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
        <span class="pl-c1">number</span>: <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">state</span><span class="pl-kos">.</span><span class="pl-c1">number</span> <span class="pl-c1">+</span> <span class="pl-c1">1</span>
      <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">bind</span><span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-c1">1000</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span>

  <span class="pl-en">render</span>: <span class="pl-k">function</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">return</span> <span class="pl-c1">&lt;</span><span class="pl-v">Middle</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">;</span>    
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-v">React</span><span class="pl-kos">.</span><span class="pl-en">render</span><span class="pl-kos">(</span><span class="pl-c1">&lt;</span><span class="pl-v">Top</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span><span class="pl-kos">,</span> <span class="pl-smi">document</span><span class="pl-kos">.</span><span class="pl-c1">body</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">The same problem would occur if I tried to give <code class="notranslate">Middle</code> a generic context-aware <code class="notranslate">shouldComponentUpdate</code> as I wrote above, because <code class="notranslate">Middle</code> has no <code class="notranslate">this.context</code> unless it opts in.</p>
<p dir="auto">This is possible to work around by adding <code class="notranslate">contextTypes</code> to <code class="notranslate">Middle</code>, but it doesn't look like a good solution. You'd need to explicitly add necessary <code class="notranslate">contextTypes</code> on every level with smart <code class="notranslate">shouldComponentUpdate</code> so it's too easy to slip up.</p>
<p dir="auto">Will this be solved by <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="41512990" data-permission-text="Title is private" data-url="https://github.com/facebook/react/issues/2112" data-hovercard-type="issue" data-hovercard-url="/facebook/react/issues/2112/hovercard" href="https://github.com/facebook/react/issues/2112">#2112</a>? Is there another solution in the meantime? What is the recommended way?</p>