First published at: github.com/USTB-musion…

Writing in the front

The rapid development of front-end technology, the rise of Vue, React, Angular, etc., bring us a new development experience. However, with the innovation of technology, as well as the improvement of front-end page complexity, there should be localStorage, eventBus, Vuex, Redux, MOBx, RXJS and other data storage and management schemes, so it is necessary to study state management. So I’ve spent some time looking into this recently. In the process of analysis may have their own understanding of the deviation or we have different understanding of the place, welcome everyone comment or private letter me.

This paper will summarize from the following parts:

  1. Data-driven view
  2. Data communication between components and eventBus
  3. Single data Flow (VUex && Redux)
  4. Better mobx
  5. Implement a super easy version of Redux and React-Redux

Data-driven view

React and VUE, the most popular front-end applications, use data-driven views, namely UI = F (state). When a page changes, you don’t need to worry about DOM changes, just state changes. The mapping of state to UI is left to the framework. To solve the performance problem, the Virtual DOM was created. With Virtual DOM, data-driven views can be broken down into four simple steps:

  • Data changes and a new Virtual DOM is generated
  • Diff algorithm is used to compare the similarities and differences between the new Virtual DOM and the old Virtual DOM
  • Generate the difference between old and new objects (patch)
  • Iterate over the difference object and update the DOM

With React and Vue, the process of state => UI became a good practice, but the reverse, how to properly modify state in the UI became a new problem. To this end, Facebook came up with the Flux idea. For details, please refer to Ruan Yifeng’s Flux Architecture primer. To put it simply, Flux is an architectural idea that sees problems with the previous MVC framework and intends to use a new mindset to manage data flows.

Data communication between components and eventBus

Data can be simply divided into two parts, data across components and data within components. Most of the data in a component is uI-related, such as whether a checkbox is checked or a button is clicked. These can be referred to as intra-component state data. In React, there is a concept called a puppet component, in which the data stored is the state data within the component. In fact, many of the UI component libraries on the market, such as Element and Ant Design, provide puppet components. Another type of data is cross-component data, such as the parent component evoking the child component to shut down. Once we face cross-component interaction, the problem becomes more complicated. A mechanism is needed to handle parent-child and sibling component communication. The parent component passes functions to its children, and the child component passes functions to its parent. In this way, the parent component passes a function to the child component, which is called by the child component. In this way, data is passed from function parameters to the parent component. Vue does this by sending data from the function arguments to the parent via $emit.

EventBus is central communication, and provide is an object or a function that returns an object. This object contains attributes that can be injected into its descendants:

The Inject option can be: an array of strings, or an object. Then use the injected value as the data entry:

But multiple views need to rely on the same state or behavior from different views needs to change the same state. Relying solely on communication between components is a bit of a chicken.

Single data Flow (VUex && Redux)

The redux and React streams look like this:

In simple terms, each event will send an action. The action triggers reducer through dispatch and directly generates a new state according to the old state to replace the original state in the top-level store.

Redux emphasizes three basic principles:

  • Unique data source
  • Keep status read-only
  • Data changes can only be done with pure functions

In the case of todo-list, the code is hosted on Github: Github

Unique Data Source: Unique data source means that the application’s state data should be stored in only one Store. The Store state tree for the Todo-List app might look something like this:

{
    todos: [
        {
            text: 'First todo',
            completed: false,
            id: 0
        },
        {
            text: 'Second todo',
            completed: false,
            id: 1
        }
    ],
    filter: 'all'
}
Copy the code

Keep the state readable: To change the state of the Store, you must do so by distributing an Action object. According to UI=render(state), to drive user interface rendering, we need to change the state of the application, but the way to change the state is not to modify the value of the state, but to create a new state object returned to Redux, Redux completes the new state assembly.

Data changes can only be accomplished by using a pure function: Reducer must be a pure function, and each reducer function format is as follows: reducer(state, action)

import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO}from './actionTypes.js'; export default (state = [], action) => { switch(action.type) { case ADD_TODO: { return [ { id: action.id, text: action.text, completed: false }, ...state ] } case TOGGLE_TODO: { return state.map((todoItem) => { if (todoItem.id === action.id) { return {... todoItem, completed: ! todoItem.completed}; } else { return todoItem; } }) } case REMOVE_TODO: { return state.filter((todoItem) => { return todoItem.id ! == action.id; }) } default: { return state; }}}Copy the code

Here is a picture from the official website to illustrate the following vuex:

Vuex is a state management tool designed specifically for VUE. Unlike Redux, which uses immutable data to represent state, Vuex does not have a reducer to create new state to replace the old state, but state in Vuex can be modified. The reason for this is related to the operation mechanism of Vue. Vue uses getters/setters in ES5 to bind views and data in both directions, so state changes in Vuex can be notified to the corresponding instructions in the view through the setter to update the view.

State in Vuex is modifiable, and the way to modify state is not through actions, but through mutations. The only way to change the state in Vuex’s store is to commit mutation.

Vuex’s data flow can be simply stated as:

  • Trigger the action in the view and pass in the required parameters based on the situation
  • Trigger the required mutation in the action and change the state in the mutation function
  • Bidirectional binding via getter/setter automatically updates the corresponding view

Better mobx

MobX makes state management easy and extensible through transparently Applying Functional Programming – TFRP. Here is a flowchart for Mobx:

Mobx is a little different than Redux. While Redux is about functional programming, Mobx is more object-oriented. Mobx has several main points:

  • Observables. Its state is observable, and both basic and reference data types can be converted to Observable value using MobX’s (@) Observable. The source
  • Reactions. It is a different concept. Computed values, or sending network requests and updating views based on observed data, are all part of response, and Reactive Programming is an application of JavaScript.
  • The Actions. It is the source of all responses, such as user actions on the view or changes in observed data resulting from a response to a network request.

Implement a simplified version of Redux and React-Redux

Simple realization of Redux createStore, Dispatch, Subscribe, Reducer, getState methods

function createStore (reducer) {
  let state = null
  const listeners = []
  const subscribe = (listener) = > listeners.push(listener) // The observer mode implements monitoring of data changes
  const getState = () = > state
  const dispatch = (action) = > { // Used to modify data
    state = reducer(state, action) Reducer accept state and actions
    listeners.forEach((listener) = > listener())
  }
  dispatch({}) // Initialize state
  return { getState, dispatch, subscribe } // Three methods are exposed
}
Copy the code

React-redux Provider, connect, mapStateToProps, mapDispatchToProps

Implement the Provider method:

export class Provider extends Component {
  static propTypes = {
    store: PropTypes.object,
    children: PropTypes.any
  }

  static childContextTypes = {
    store: PropTypes.object
  }

  getChildContext () {
    return {
      store: this.props.store
    }
  }

  render () {
    return (
      <div>{this.props.children}</div>
    )
  }
}
Copy the code

So you can use

<Provider store={store}>
    
</Provider>
Copy the code

The root component is wrapped.

MapStateToProps and mapDispatchToprops

export const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => { class Connect extends Component { static contextTypes = { store: PropTypes.object } constructor () { super() this.state = { allProps: {} } } componentWillMount () { const { store } = this.context this._updateProps() store.subscribe(() => this._updateProps()) } _updateProps () { const { store } = this.context let stateProps = mapStateToProps ? MapStateToProps (store.getState(), this.props) : {} let dispatchProps = mapDispatchToProps? MapDispatchToProps (store.dispatch, this.props) : {} // If mapDispatchToProps is not passed this. SetState ({allProps: {... stateProps, ... dispatchProps, ... this.props } }) } render () { return <WrappedComponent {... this.state.allProps} /> } } return Connect }Copy the code

conclusion

If the project stack is based on VUE, vuex is a better choice for state management. But if the technology stack is based on React, it’s a matter of opinion between Redux and Mobx. The reason for choosing Mobx may be that there is not as much flow as Redux, and changing a state requires looking for code in several files. There is a low cost of learning, may be able to read the document to get started. However, the disadvantage is that it is too free and offers very few agreements, which makes it a bit boring to do large projects. Redux puts a lot of restrictions on developers, but even those restrictions make it harder to mess up on large projects.

Refer to the article

Vuex Chinese document

Redux Chinese document

Discussion on Front-end State Management (PART 1)

Think again about front-end state management

Front-end data management and front-end framework selection

You can pay attention to my public account “Muchen classmates”, goose factory code farmers, usually record some trivial bits, technology, life, perception, grow together.