In business, the MVVM framework is usually used together with the data state library (REdux, MOBx, etc.). This article will explain why the data state library is introduced through a small demo.

Start with the MVC to MVVM pattern

One of the headaches with traditional MVC architectures (such as JSP) in today’s era of mobile traffic is that they do a lot of global repetitive rendering. However, MVC architecture is a good thing, because it has a clear division of labor for data, view and logic, so the front-end MVC framework (such as backbone.js) comes out. For many scenarios with small business scale, the front-end MVC framework is enough, and it can also achieve the development of single-page applications separated from the front and back ends. So what’s the downside?

Take backbone.js for example, its Model exposes the set method, that is, it can modify the data of the same Model in more than one View, and then the data of one Model corresponds to the presentation of multiple views at the same time, as shown in the figure below. When there is too much business logic, multiple models and multiple Views are coupled together, which can be a pain to troubleshoot.

MVVM framework perfectly solves the problems of low performance (multiple global rendering) of traditional MVC architecture and high coupling degree (Model and View) of front-end MVC framework. Refer to the bidirectional binding that the MVVM framework parses as written earlier

only MVVM

Suppose you have a scenario where you query the criteria in the input box, click Query, and return them in the list. As shown below:

If react is implemented, the main idea is to call the query interface first, and then use setState to store the obtained data into the list. The list shows the following code:

const Decorate = (ListComponent) = > class extends Component {
  constructor() {
    super(a)this.state = { list: [] }
  }

  componentDidMount() {
    fetch('./list.json')
      .then((res) = > res.json())
      .then(result= > this.setState({ list: result.data }))
  }

  render() {
    return (
      <ListComponent data={this.state.list} />)}}Copy the code

Next, we pass a List component that’s built using stateless functions to display the List data on our packaged component:

function List(props) {
  return (
    <div>
      {props.data.map(r =>
        <p key={r.id}>{r.content}</p>
      )}
    </div>)}Copy the code

You can see that the List component is like the View layer, and the packaged Class component is like the Model layer. But doing so still writes the business logic into the component. What we want is a pure Model layer and a pure View layer. Let’s take a look at how the Flux architecture pattern solves this problem.

Invoke the Flux schema

The four important components of the Flux architecture pattern and their relationship are shown in the figure above. The veil of the Flux architecture pattern will be gradually revealed in the order of Dispatch, Store, Action, and View below.

It can be seen from Flux’s source code that dispacher.js is its core file, and its core is completed by event-based publish/subscribe mode. The core source code is as follows:

class Dispatcher {...// Register the callback function,
  register(callback) {
    var id = _prefix + this._lastID++;
    this._callbacks[id] = callback;
  }

  // The registered callback function is called when dispatch is called
  dispatch(payload) {
    this._startDispatching(payload);
    for (var id in this._callbacks) {
      this._invokeCallback(id); }}}Copy the code

Review the previous purpose: to make the Store layer pure. We define a variable comments to store list data. After knowing the core principle of Dispatcher, when we call dispatch(OBj), we can pass parameters to the register function, as follows:

// commentStore.js
let comments = []
const CommentStore = {
  getComment() {
    return comments
  }
}

dispathcer.register((action) = > { // Call register on the Dispatcher instance
  switch (action.type) {
    case 'GET_LIST_SUCCESS': {
      comments = action.comment
    }
  }
})
Copy the code

And the functions in action are as follows:

// commentAction.js
const commentAction = {
  getList() {
    fetch('./list.json')
      .then((res) = > res.json())
      .then(result= >
        dispathcer.dispatch({ // Call the dispatch function on the Dispatcher instance
          type: 'GET_LIST_SUCCESS'.comment: result.data
        }))
  }
}
Copy the code

But there seems to be something missing. When GET_LIST_SUCCESS succeeds, it is found that there is also a lack of ability to notify the page to call commentStore.getcomment () again, so again reference the event publish/subscribe mode, This time I used the events module provided by Node.js to modify the commentStore.js file as follows:

let comments = []
const CommentStore = Object.assign({}, EventEmitter.prototype, {
  getComment() {
    return comments
  },

  emitChange() {
    this.emit('change')
  },

  addListener(callback) { // Make it available to page components
    this.on('change', callback)
  }
})

appDispathcer.register((action) = > {
  switch (action.type) {
    case 'GET_LIST_SUCCESS': {
      comments = action.comment
      CommentStore.emitChange() // With this line of code, you now have the ability to notify the page to call CommentStore.getcomment again}}})Copy the code

The last step is to integrate the store and action into the page as follows:

class ComponentList extends Component {
  constructor() {
    super(a)this.state = {
      comment: commentStore.getComment()
    }
  }

  componentDidMount() {
    commentStore.addListener((a)= > this.setState({ // Register functions, as mentioned above, for store use
      comment: commentStore.getComment()
    }))
  }

  render() {
    return (
      <div>
        {this.state.comment.map(r =>
          <p key={r.id}>{r.content}</p>
        )}
      </div>)}}Copy the code

summary

Building applications using MVVM alone will find that business logic and data are coupled in components. After introducing the Flux architecture pattern, data and business logic are better separated. But what are the disadvantages of using Flux? I’ll see you in the next post, Talking about Redux Architectural Patterns.

This practice case has been uploaded to stateManage

Series blog, welcome Star