Why want to write this topic, because the first is because share week will set up a flag to say, but I don’t want to share some of what the class library, because some other class library for our business, and no special good help, second before chatting with colleagues, and he asked me a question, “how do you do for the new library, New API to keep the continuous learning enthusiasm, “I am so answer his” business “because it is over, ha ha, everyone will think I am bullshit, but in fact it makes sense, some new API, the new library is in fact in order to solve the problem of some of the history, when you are in the current environment to solve some complex problems and have a headache, When you tackle it in a roundabout way and find a new pattern to tackle, you stay excited and excited. This time, we’ll take a look at the React chronicle with some perspective. We hope you can review some of the React history issues that you haven’t encountered before, and also see why the new React API was created to help developers.

Earlier than 0.14.x (2015年)

Prior to 0.14x, ES6 was not common, so when you created a React class, you would create a function call that would pass in key values that would lifeCycle, state, and props to that function.

A common, basic component with props and state is organized in this way

var Counter = React.createClass({
	getInitialState: function() {
		return {
			count: 0
		}
	},
	getDefaultProps: function() {
	    return {
	    	name: 'Mary'
	    };
	},
	componentDidMount: function() {
		this.setState({
			count: this.state.count + 1
		})
	},
	handleClick: function() {
this.setState(function(preState) {
			return {
				count: preState.count + 1
			}
		})
	},
	render: function() {
		return (
			<div 
			  onClick={this.handleClick}
			>
				{this.state.count}
			</div>
		)
	}
})
Copy the code

JSX

Jsx and ES6 versions are essentially indistinguishable

State

The initial value of state is created from the return value of the function call of initialState

handler Method

No ES6: One of the biggest differences between method calls and the ES6 version is that for ES6, we all know that it has to manually bind this. This is not required for react.createclass because in older versions of the reactClass object, all key values passed into the CreateClass object are iterated during initialization. The default built-in lifCycle will follow the default behavior. But anything that is not lifeCycle will go through a judgment loop and the source code will not be available for lifeCycle [github.com/facebook/re…]

if (this.__reactAutoBindMap) {
  	bindAutoBindMethods(this);
}

function bindAutoBindMethods(component) {
  for (var autoBindKey in component.__reactAutoBindMap) {
    if (component.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
      var method = component.__reactAutoBindMap[autoBindKey];
      component[autoBindKey] = bindAutoBindMethod( component, method ); }}}Copy the code

This, above, is the context for the entire ReactClass, and this is how autoBind is implemented for the handler.

Es6: JS missing this problem

var obj = {
a: 123,
	test: function() {
console.log(this.a)
	}
}
function render(func) {

    func()
}

render(obj.test)
Copy the code

There are two things you can learn just by comparing React instances with the old and new syntax

  • Es5react. createClass method body why not bind this
  • Problem with ES6Class extends React.Component this pointer

Class Extends

Basic to Class OOP is the Richter Substitution principle, which states that wherever a base class can occur, a subclass must occur. That is, if, for example, you have a BaseHeader, and one of the subclasses integrates BaseHeader, called HeaderWithAvatar, then all BaseHeader places can be replaced with HeaderWithAvatar, which is called the same type of component.

To be sure, using inheritance for logical reuse is fine, but it has limitations

Take a look at the code

export class BaseHeaderInh extends React.Component {
  state = {
    classname: 'base'
  }
  componentDidMount() {
    console.log('shit')}render() {
    return (
      <div className={this.state.classname}>HeaderInh base</div>
    )
  }
}

export class HeaderInh extends BaseHeaderInh {
  componentDidMount() {
    console.log('bull shit')
  }
  componentWillReceiveProps(nextProps) {
    // code for base components/*  */
    console.log('base componentWillReceiveProps')
  }
  state = {
    classname: `${this.state.classname} red`
  }
}

export class HeaderReadAvatar extends HeaderInh {
  componentWillReceiveProps(nextProps) {
    super.componentWillReceiveProps()
    console.log('i want change somethin in domain props')}render() {
    return (
      <div>
        {super.render()}
        icon
      </div>
    )
  }
}
Copy the code
  • Override for lifeCycle or Method will cause the component to not perform as expected
  • Severely coupling the relationship between subclasses and superclasses
  • You can’t safely implement subclass-specific scenarios without carefully reading base classes.
  • Code must be carefully written

Phase 2 summary: What are the problems with react-based inheritance logic reuse

For the React philosophy, developers are expected to have a single responsibility for each component to decouple, for example, HOC, render props mode.

The high degree of inheritance coupling makes it more difficult to use in React mode, which is an obvious problem.

Each component of the combination is separated, so the combination more conforms to the principle of single responsibility, and the combination can make better use of children, state, and props.

After all, inheritance is a polymorphic tool, not a code reuse tool, and when you use composition to implement code reuse, there is no inheritance relationship. Overusing inheritance, if you modify the parent class, will break all of the subclasses. This is because the tight coupling between subclasses and superclasses occurs at compile time.

Mixins

var SetIntervalMixin = {
  componentWillMount: function() {
    this.intervals = [];
  },
  setInterval: function() {
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() { this.intervals.forEach(clearInterval); }}; var TickTock = createReactClass({ mixins: [SetIntervalMixin], // Use the mixin getInitialState:function() {
    return {seconds: 0};
  },
  componentDidMount: function() {
    this.setInterval(this.tick, 1000); // Call a method on the mixin
  },
  tick: function() {
    this.setState({seconds: this.state.seconds + 1});
  },
  render: function() {
    return (
      <p>
        React has been running for{this.state.seconds} seconds. </p> ); }});Copy the code
  • The Mixins core source code is basically the same mechanism as autoBind, but I’ll go into more detail.
  • The problem with Mixins is similar to that with class extends
  1. Mixins create implicit dependency assumptions, you have a component that has a state count = 1, and then a colleague creates a mixins, a generic mixins, to read the count in the local state and handle some reuse logic, and after a few months, you want to do some state-sharing business, Passing count to someone else does a state boost, pushing count up to the parent component, at which point the mixins explode. And mixins can depend on each other, so removing one might cause the other to explode. In this case, it is difficult to accurately describe the dependencies between mixins

  2. Mixins have naming conflicts

  3. Similar to class inheritance problems

In response to the above problems, React and even a team of excellent engineers like Facebook would encounter the above problems and fail to properly organize, reconstruct, and maintain such complex problems. Obviously, mixins are a bad design.

Therefore, for logical reuse, component reuse, as time goes by and experience advances, the most familiar higher Order Component appears.

Higher Order Component

It perfectly solves all the above problems. For logical reuse, component reuse can be well handled, just because HOC appears in the form of combination. Hoc doesn’t need much introduction. But hoc still has some problems:

  1. Redundant nested higher-order components, such as the extensive use of Hoc in the Reach Router. A basic routing display shows up with seven layers of hoc.
  2. After multiple hoc combinations, the same props cannot be named to distinguish which hoc is derived from, so render props appears

Render Props

All hoc can be rewritten by Render props, which eliminates all the problems of hoc. The writing method is more elegant, but it needs to be divided into different scenes. Personally, I don’t think it’s true that all logic reuse hoc is rewritten with render props. There are some scenarios where there is no need to use render props, for example, for permission issues. Because render props is, after all, a JSX, it can’t solve problems externally, but rather inside the Render function.

function isAuth(Component) {
  return class Auth extends React.Component {
    state = {
      auth: false
    }
    componentDidMount() {
      setTimeout(() => {
        this.setState({ auth: true}})}, 300)render() {
      return( <div> {this.state.auth ? <Component {... props} /> :'Not allowed to view'}
        </div>
      )
    }
  }
}
@isAuth
class Demo extends React.Component {

}

// render props
class Auth extends React.Component {
  state = {
    auth: false
  }
  componentDidMount() {
    setTimeout(() => {
      this.setState({ auth: true})
    }, 300)
  }
  renderError = () => {
    return(
      <div>Error component</div>
    )
  }
  render() {
    return (this.props.children({
      auth: this.state.auth,
      renderError: this.render
    }))
  }
}


class RenderProps extends React.Component{
  render() {
    return(
      <div>
        <Auth>
          {({auth, renderError}) => {
            return <div>
              {auth ? Component : renderError}
            </div>
          }}
        </Auth>
      </div>
    )
  }
}
Copy the code

With Hoc there is almost no intrusion into JSX, just a decorator ora function return component, but with render props there is definitely an intrusion into JSX, which means you need to have a reasonable JSX structure to organize, no matter what.

For example, the bottom div needs multiple createContext props, so it needs to be like this.

class Demo extends React.Component {
  render() {
    return( <Auth> {({ auth, renderError }) => ( <Game> {(props) => ( <Dude> {(props) => ( <Shit> {props => ( <div>213</div> )} </Shit> )} </Dude> )}  </Game> )} </Auth> ) } }Copy the code

In addition to solving almost all of the current issues, the Hooks API solves some additional issues

  • The amount of code compiled
  • Looks a little more FP (just looks)
  • Reduce the error rate of retarded code
  • Make more components easier to test

Stage summary:

  • Mixins(0.14x<) : logic reuse of the first generation, although the solution to logic reuse, but the nature of Class inheritance similar problems (engineering cooperation will cause trouble)

  • Class Inheritance: is a polymorphic tool, not a code reuse tool (requires very complete OOP capability, but does not solve coupling problems)

  • Higher Order Component(0.14X-15.6) : Logic code reuse occurs in the form of combination, with moderate granularity and complete state and props forms, which meets the single responsibility principle of React core (but causes the problem of redundant nested components)

  • Render Props(16.x) : Gracefully handle hoc residuals, but still might Call BackHell

  • Hooks (16.7 alpha) : basically a solution for logic reuse at this stage

From 0.14.X to 16.6 (2016 to 2017 and 8), there have been numerous API updates, continuous improvements to the Reconciler’s architecture, and unpacking, such as ReactDom, React.csstransitionGroup, React.CreateClass, react. PropTypes, etc., including starting to add Fiber architecture in later code enhancements, ComponentDidCatch, getDerivedStateFromProps, GetSnapShotBeforeUpdate and so on

16.x RoadMap

In addition to some we have been exposed to, there are the following two details (these two details can actually be found from the official website and the lecture video of Iceland Dan)

  • 16.8: concurrent mode
  • 16.9: Girl for Data fetching

So just to conclude

With so many frameworks and apis that are changing rapidly, I, for one, am eager to learn from them by solving business and problem solving ideas.

  1. To find truth in history,
  2. Iterating through the process,
  3. Try them in business