Skip to content

Instantly share code, notes, and snippets.

@soareschen
Last active July 13, 2016 10:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save soareschen/18be42ac527388bd3f4d to your computer and use it in GitHub Desktop.
Save soareschen/18be42ac527388bd3f4d to your computer and use it in GitHub Desktop.
Managing State in React

Managing State in React

After digging more into React I get a better idea on how React states work. It looks like React still have a bit of magic happening behind the scene to make states work.

// 3 Elements mapping to the same real DOM
var element1 = <MyElement awesome=true>My Awesome Content</MyElement>

var element2 = <MyElement awesome=false>My Boring Content</MyElement>

var element3 = React.createElement(MyElement, {
  awesome: true }, "My Other Content")

Every time you create an element in React, the JSX compiler compiles it into code that creates a ReactElement object. Every time your render function is executed, a new ReactElement object is created. You can also create ReactElement objects many times anywhere you like. Each of these elements can have different properties, which you can infer just by looking at the code.

Note that ReactElement is created from a ReactClass, and ReactComponent created from rendering a ReactElement to a real DOM. ReactComponent is the one that has render(), setState(), and other methods that we are familiar with.

The rendered ReactComponent will get the props that was defined in the ReactElement. But states in React is a bit magical. You can create many ReactElement objects, but they can share the same state object.

Behind the scene when your render() function is called, ReactElement objects are created with empty state. React will then use this ReactElement object as virtual DOM to compare with the current DOM tree. And once it finds out there is an equivalent ReactComponent at the same position, it will reuse that ReactComponent and simply assign the new props to it. In other words, you can have many ReactElement objects with different props but the result ReactComponent will all share the same state.

This is also why it is a bad idea to set a ReactComponent state based on its current props. Once the state is set, any changes to props are ignored and React will ended up rendering old props.

The stateful mechanism in React solves some important problems of managing state of user interfaces. It is more elegant than other approaches such as two-way data-binding, but perhaps not elegant enough. In my opinion having magical shared states make it hard to reason about programs. By just looking at the element declaration code, we cannot easily reason how the output would look like, because of the hidden states. The states also can't be manipulated easily, and that makes it hard for testing if we just want to see how the UI at a particular state would look like.

Fortunately the good news is that React is heading toward the right direction, and I can think of a simple design pattern to separate the evilness of state.

// original
var MyElement = React.createClass({
  onSomeEvent: function() {
    this.setState(...)
  },
  render: function() {
    return (
      <div some-attr={this.state.activated}>{this.props.content}</div>
    )
  }
}) 

If you look at stateful React elements, when the state changes and render() is called, the state of that element usually becomes the props of its children element. If we generalize that pattern, we want to convert all states into props and put them in separate structures. In other word for every stateful React elements we can create two separate React classes: a stateful React class that wrap over a stateless React class:

// separated
var MyStatefulElement = React.createClass({
  onSomeEvent: function() {
    this.setState(...)
  },
  render: function() {
    return (
      <MyStatelessElement activated={this.state.activated} {...this.props}>
    )
  }
})

var MyStatelessElement = React.createClass({
  render: function() {
    return <div some-attr={this.props.activated}>{this.props.children}</div>
  }
})

This way it will be much easier to reason about the program. Using some dynamic settings, we could create two separate React class hierarchy - one which is stateful and the other is stateless with all states converted to props. The stateless classes can then be easily tested with each possible state by simply setting the props.

Other than that, a stateless React class can essentially be reduced to a render() pure function.

function render(props) => ReactElement

And a stateful wrapper would have event listeners and a function to merge props and state.

function stateMapper(props, state) => props

After the transformation, the stateful React class really doesn't do much other than listening to events and changing state. The rest of the boilerplate code is just there to trigger the rerendering and use the mapper function to merge the state with props. I strongly believe this can be further abstracted into some other design pattern, as it doesn't have anything to do with rendering anymore.

Looking at the function signature carefully, the stateless render function can be generalized to be considered a model function rendering a model plain object and returns a virtual DOM.

function template(model) => VDOM

Conclusion

In summary, I introduce a simple design pattern to separate stateful and stateless logic in React application. Right now I cannot be sure if I am 100% correct on my understanding, since I have only learn React for a few days. Feel free to correct me if I am wrong with anything about React.

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