From 9abd1133c94288c09512f7cf0b8a0b8136df6da7 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 23 Jan 2015 10:08:40 -0800 Subject: [PATCH] Pass context to the constructor This should reenable reading this.context from getInitialState. Added a bunch of tests for this too. --- src/classic/class/ReactClass.js | 3 +- .../class/__tests__/ReactClass-test.js | 30 ++++++++++++++++++ src/core/ReactCompositeComponent.js | 2 +- src/modern/class/ReactComponentBase.js | 3 +- .../class/__tests__/ReactES6Class-test.js | 31 +++++++++++++++++++ 5 files changed, 66 insertions(+), 3 deletions(-) diff --git a/src/classic/class/ReactClass.js b/src/classic/class/ReactClass.js index cd1f2fb403..b5359d076b 100644 --- a/src/classic/class/ReactClass.js +++ b/src/classic/class/ReactClass.js @@ -805,7 +805,7 @@ var ReactClass = { * @public */ createClass: function(spec) { - var Constructor = function(props) { + var Constructor = function(props, context) { // This constructor is overridden by mocks. The argument is used // by mocks to assert on what gets mounted. @@ -815,6 +815,7 @@ var ReactClass = { } this.props = props; + this.context = context; this.state = null; // ReactClasses doesn't have constructors. Instead, they use the diff --git a/src/classic/class/__tests__/ReactClass-test.js b/src/classic/class/__tests__/ReactClass-test.js index e2aeb41b48..b0d3b45b5a 100644 --- a/src/classic/class/__tests__/ReactClass-test.js +++ b/src/classic/class/__tests__/ReactClass-test.js @@ -278,6 +278,36 @@ describe('ReactClass-spec', function() { expect(instance.state.occupation).toEqual('clown'); }); + it('renders based on context getInitialState', function() { + var Foo = React.createClass({ + contextTypes: { + className: React.PropTypes.string + }, + getInitialState() { + return { className: this.context.className }; + }, + render() { + return ; + } + }); + + var Outer = React.createClass({ + childContextTypes: { + className: React.PropTypes.string + }, + getChildContext() { + return { className: 'foo' }; + }, + render() { + return ; + } + }); + + var container = document.createElement('div'); + React.render(, container); + expect(container.firstChild.className).toBe('foo'); + }); + it('should throw with non-object getInitialState() return values', function() { [['an array'], 'a string', 1234].forEach(function(state) { var Component = React.createClass({ diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js index aa0af8c092..fd9eed50a0 100644 --- a/src/core/ReactCompositeComponent.js +++ b/src/core/ReactCompositeComponent.js @@ -169,7 +169,7 @@ var ReactCompositeComponentMixin = assign({}, ); // Initialize the public class - var inst = new Component(publicProps); + var inst = new Component(publicProps, publicContext); // These should be set up in the constructor, but as a convenience for // simpler class abstractions, we set them up after the fact. inst.props = publicProps; diff --git a/src/modern/class/ReactComponentBase.js b/src/modern/class/ReactComponentBase.js index a3308f64ff..fcdc0e2b79 100644 --- a/src/modern/class/ReactComponentBase.js +++ b/src/modern/class/ReactComponentBase.js @@ -19,8 +19,9 @@ var warning = require('warning'); /** * Base class helpers for the updating state of a component. */ -function ReactComponentBase(props) { +function ReactComponentBase(props, context) { this.props = props; + this.context = context; } /** diff --git a/src/modern/class/__tests__/ReactES6Class-test.js b/src/modern/class/__tests__/ReactES6Class-test.js index 527916b7a5..ffeddabda3 100644 --- a/src/modern/class/__tests__/ReactES6Class-test.js +++ b/src/modern/class/__tests__/ReactES6Class-test.js @@ -98,6 +98,37 @@ describe('ReactES6Class', function() { test(, 'SPAN', 'bar'); }); + it('renders based on context in the constructor', function() { + class Foo extends React.Component { + constructor(props, context) { + super(props, context); + this.state = { tag: context.tag, className: this.context.className }; + } + render() { + var Tag = this.state.tag; + return ; + } + } + Foo.contextTypes = { + tag: React.PropTypes.string, + className: React.PropTypes.string + }; + + class Outer extends React.Component { + getChildContext() { + return { tag: 'span', className: 'foo' }; + } + render() { + return ; + } + } + Outer.childContextTypes = { + tag: React.PropTypes.string, + className: React.PropTypes.string + }; + test(, 'SPAN', 'foo'); + }); + it('renders only once when setting state in componentWillMount', function() { var renderCount = 0; class Foo extends React.Component {