This series is divided into three parts: Framework Implementation, Framework Usage and Data Flow Philosophy. These three articles are my periodic summaries of data flow and complement the outdated ones.

This is the final work “Front-end Data Flow Philosophy”.

1 the introduction

While writing this article, I am under a lot of pressure. If there is anything inappropriate, please correct me.

Also, since this is a Buddhist article, it doesn’t follow that you should use the xyz framework, you should read it for pleasure.

2. Intensive reading

First of all, there are three popular data flow management modes.

  • Functional, immutable, patterned. Typical implementation: Redux – The epitome of justice.
  • Responsive, dependent tracing. Typical implementation: Mobx.
  • Reactive, unlike upstairs, is implemented as a flow. Typical implementation: Rxjs, XStream.

Of course, there is a fourth mode, streaking, which is actually quite healthy sometimes.

The general criteria for the use of data flow are: side effect isolation and reasonable division of global and local state. All the above three data flow management modes can be realized, except whether they are forced or not.

2.1 Start with the chronological order

I’ve been thinking about how to connect these three thoughts, and when I figured it out, it was natural to connect them chronologically.

Skip Prototype, jquery era, why skip? Because the front-end was in the age of barbarians, and the survival problem was not solved, there was no time to think about data flow, design patterns? The front end was also considered more watery than the back end at that time.

As the front end gets healthier, potholes are being filled in, hardware performance is improving, and requirements are getting more complex, it’s time to think about how to organize your code.

The first thing you see is Angular. The idea of MVVM has opened up a new world for the front end. While Angluar was heavy to use, the data-driven ideas that MVVM brought to the table became more and more popular, and React suddenly became popular.

In fact, before React became popular, there was a framework in place that entered the React + Mobx era. That’s avalon. Avalon was also very popular, but for a framework to succeed, it had to be in the right place at the right time, and the time was not right. People were tired of Angular, and most of them jumped into react’s arms.

It may be a bit subjective, but I think react has caught on because people think it’s lightweight. Angular + is a data-driven version of angular +, and it’s very relevant to The Times. There are a lot of concepts around angular, such as state-driven, one-way data flow, and so on.

Although react has a built-in fractal dataflow management architecture, it always emphasizes that it is just a View layer, and data-layer enhancement frameworks continue to emerge, ranging from Flux, Reflux, and Redux. I have to say react has really pushed the independence of data flow management and reintroduced the importance of data flow management.

Redux is so far ahead of its time that it forces side effects to be isolated in one step, but we both love and hate it for not addressing the code redundancy that comes with it, so some people are turning to Mobx, a responsive data flow framework that doesn’t force side effects to be isolated, so it’s comfortable to write.

Of course mobx would not have caught on if it were just MVVM, angular is there. With the React train and a lot of criticism of Angular’s dirty detection efficiency, Mobx has become popular. Of course, as a front-end mission is to optimize human-computer interaction, so we all know that user habits are the most difficult to change, until now, Redux is still absolutely mainstream.

When Mobx was still being promoted in a small scope, another more obscure field was just in its infancy, namely, the framework represented by RXJS, which shared the same observable term with Mobx. Mobx did not understand it clearly, and few people knew about RXJS.

As Mobx took off, I created a similar library: DOB. The main motivation was that MOBx didn’t feel perfect enough, and some API modifications like extendObservable were needed for new assignment variables. It happened that browser support for proxy was mature, so I replaced MOBx with DOB for almost all my personal projects.

If react + Mobx works so well, why not use Vue? “I was moved by the flag of.

Until now, the front end has evolved to the point where typescript has beaten flow to become the new JS, and with ember and Clojurescript, js has been compiled in a variety of languages. With support for compiling to WebAssembly, react authors abandoned JS to create a new language, Reason.

I wrote a preliminary understanding of Reason for intensive reading.

Can the next set of spiritual baptism of the front people, has raised the heart of calm, niche has not become a threshold across the comfort zone, and then learn a RXJS what? (Just kidding, the RXJS community is full of great people who have been working on it for years.) So RXJS is getting hot again recently.

So, in terms of chronological order, we can read the three frameworks in terms of the order of Redux-Mobx-RxJS.

2.2 What does Redux bring

Redux is a framework that enforces the use of the global Store, despite numerous attempts to localize it.

Part of this, of course, was due to epochal responsibility, which required a global state management tool to compensate for the react local data flow. The most important reason is that Redux has an almost squeaky-clean orientation that is clear and traceable.

Almost everything is prepared for those two words. The first step is to separate side effects, because side effects are the first obstacle to code clarity and traceability, so the action + Reducer concept came on stage and perfectly solved the side effects problem. Perhaps referring to the design of koA middleware, Redux Middleware exposes the developer control of actions over the black box received from the Reducer.

The functional buzz generated by reading redux Middleware’s source code may be helping developers feel better about RXJS. At the same time, the concept of higher-order functions is also reflected in the middleware source code, almost paving the way for the react higher-order components.

Redux-thunk, Redux-Saga, and the idea of asynchronous isolation brought by Redux have become popular. At the same time, a set of high-level packaging frameworks based on this also emerge in endlessly, it is recommended to use a good, such as DVA.

The second step is to tackle the “object reference” mechanism that impedes backtracking, bringing the big idea of immutable to the front. None of the states are changed, and the redux-dev-tools “time machine” feature based on this is impressive.

Intensive reading Immutable is a shared construct.

Of course, redux’s ts support is cumbersome due to dispatch, which is very much like an event mechanism, so maintenance of redux projects requires frequent use of full-text search and at least hopping between two files.

2.3 What does Mobx bring

Mobx is a very flexible TFRP framework, a branch of FRP, which makes FRP transparent and automatic.

From functional (FP), to FRP, to TFRP, the relationship is just extended, does not mean that the longer the word, the better.

Having said that, mobx is growing fast because of redux fatigue, but now there’s another way to look at it.

Mobx comes up with concepts that are similar to RXJS in some ways, such as how amazing their Observables are. So what is an Observable?

An Observable can be thought of as a signal source. Every time the signal changes, the flow automatically executes and outputs the result, which, in the case of the front end, eventually refreshes the view. That’s the data-driven view. However, MOBX is a TFRP framework, which automatically triggers dispatch of data sources whenever a variable changes, and each view automatically subscribs to each data source, which we call dependency tracking, or automatic dependency binding.

I still think TFRP is the most efficient way to develop, auto-subscribe + auto-publish, and nothing is more efficient.

But there is a downside to this pattern, which causes side effects to contaminate the pure functions, just as Redux combines actions with reducer. Also, a direct modification to props would conflict with the immutable definition of react for props. So Mobx later came up with an Action solution that addressed the conflict with react props, but did not address the issue of unforced separation of side effects.

In my opinion, side effects and mutable are two things, and the relation between them will be explained later. The fact that MOBx does not solve side effects does not mean that TFRP cannot isolate side effects, and that mutable does not necessarily conflict with traceability. For example, mobx-state-tree communicates with Redux by means of mutability.

The front-end exploration of data flow continues, with Mobx first offering a unique mechanism and then finding a junction with Redux.

2.4 What does RXJS bring

RXJS is another branch of FRP. It is based on Event Stream, so it is not as intelligent as MOBX in terms of auxiliary function for View. However, the definition of data source is fundamentally different from TFRP. Frameworks like RXJS can turn almost any event into a data source.

At the same time, RXJS is very powerful in handling data streams. When we convert everything on the front end to the data source, everything else is converted by the all-powerful RXJS. You’ll find that the side effects are completely isolated in the data source transformation layer, and then you’ll enter the beautiful world of pure functions. Finally output to the DOM driver rendering, if coupled with the virtual DOM embellishment, that is not. Is it not cycleJS?

By the way, RXJS is very capable of abstracting pure functions from data streams, so the front end is all about pulling out a tool that translates side effects such as events, requests, and pushes into data sources. Cyclejs is one such framework: it provides a set of libraries described above, and docking with the DOM adds virtual DOM capabilities.

RXJS brings a new perspective to front-end data flow management solutions. Its concept was inspired by Mobx, but its approach is similar to Redux.

RXJS brings two new approaches to development. The first is a CycleJs-like approach that converts any front-end side effects into a data source and connects directly to the DOM. The other is similar to Redux-Observable, which integrates RXJS data flow processing capabilities into existing data flow frameworks.

Redux-observable changes actions and reducer into stream mode. It also converts packaged functions into data sources for side effects in actions, such as making requests. Therefore, side effects in Redux Middleware, It was transferred to the data source transformation, which kept the actions pure function and increased the data processing capacity of reducer, which was originally pure function. It was great.

If Redux-Saga solves asynchracy, redux-Observable solves side effects and gives away RXJS data processing power.

Looking back at MOBx, both RXJS and MOBx have enhancements to Redux, and the development of front-end data flow is constantly blending.

We not only link redux, MOBx and RXJS together in the timeline, but also find their internal connections. These three ideas are like a complex web.

2.5 What can be strung together

We found that Redux and RXJS completely isolate side effects because they have one thing in common: the abstraction of front-end side effects.

Redux isolates the effects from the Reducer by doing side effects in the action, making the Reducer a pure function.

RXJS turns side effects into data sources first, isolating them from pipeline flow processing.

Mobx, alone, lacks the side effects abstraction layer, which leads to better code than Redux and RXJS, but side effects are mixed up with pure functions, so they are not functional.

Some would argue that mobx is a direct mutable object that causes side-effects. Yes, and no.

obj.a = 1
Copy the code

This code must be mutable in JS, right? Not necessarily, and not necessarily in languages like c++ where operators can be overloaded. Setter syntax doesn’t necessarily modify the original Object, for example, you can override setter events on obj objects via object.defineproperty.

We can then imagine that by overloading the operator, a mutable way is immutable. The use of variable data structures has been explained in my blog, Redux, and the use of variable data structures. Mweststrate strate:

autorun((a)= > {
  snapshots.push(Object.assign({}, obj))
})
Copy the code

The idea is simple: Save a snapshot of the object when it changes, even if there are performance issues. This simple idea is a good start, but it is possible to convert mutable to immutable with a little modification at the framework level.

For example, immer uses proxy metaprogramming to rewrite setters as Object.assign() to convert mutable to immutable.

The author’s dob-redux is also converted from mutable to immutable by calling immutablejs.set () via proxy.

Does the component need data flow

It really depends on the scene. First, components of business scenarios are suitable for binding to global data flows, while generic components that are business-independent are not. At the same time, for complex generic components, fractal-supporting data flows can be bound for better internal communication.

However, if data flow refers to RXJS processing of data, then RXJS is suitable for any situation that requires complex processing of data. Also, if data flow refers to the categorization of side effects, any side effects can be turned into a data source normalization using RXJS. You can also encapsulate side effects as events, or promises.

For side effect normalization, the author thinks RXJS is more suitable. First, the event mechanism is similar to RXJS. In addition, promise can only return once, and resolve Reject can return multiple times, while Observable can return multiple times without built-in state. So you can be more flexible in how you represent the state.

Therefore, for various business scenarios, you can first consider external conditions such as manpower, project importance, and subsequent maintenance costs, and then determine whether to use specific components in a project based on their application scenarios, such as whether to bind them to services, and how to use data flows.

Layout and style work may be replaced by AI in the near future, but data-driven data flow selection should be difficult to replace by AI.

React + MOBx: Vue

First of all, there is a lot of truth and weight in this sentence, but TODAY I will think from a new Angle.

As you can see from the previous discussion, the front-end development process is now divided into three parts: side effect isolation -> data flow driven -> View rendering.

First, view rendering, whether JSX or Template, is the same and interchangeable.

React/AG /vue + Redux /mobx/ RXJS/any combination of react/ AG/Vue + Redux /mobx/ RXJS/any combination of react/ AG/Vue + Redux /mobx/ RXJS/any combination of react/ AG/Vue + Redux /mobx/ RXJS/any combination of react/ AG/Vue + Redux /mobx/ RXJS

Finally, data flow drivers are built in differently in different frameworks. React has built-in redux, vue/ Angular has built-in mobx, and CycleJS has built-in RXJS.

React + Redux is the most natural. React + Mobx is just like Vue + Redux. The only thing awkward about React + Mobx is the way the data flows are driven. For view rendering, side effect isolation, these two factors are not affected by any combination.

In terms of data flow driven issues, we can think at a higher level. For example, if we regard react/ Vue/Angular syntax as three DSL specifications, we can actually use a common DSL to describe them and convert corresponding DSL to connect with different frameworks (Alibaba already has such implementation). The DSL can also mask the framework’s built-in data stream processing, for example:

<button onClick={() => {
  setState(() => {
    data: {
      name: 'nick'
    }
  })
}}>
  {data.name}
</button>
Copy the code

If we convert the above generic JSX code into a generic DSL, the structure and methods will be described in a generic way, while the react/vue/ Angluar code will be translated into the implementation of the built-in data flow scheme.

In fact, the built-in data stream style can be ignored after the upper level abstraction. We can even use proxy to convert the mutable code to immutable mode when transferring to Vue, and keep the mutable form when transferring to Vue.

The higher the abstraction of framework encapsulation, the less the differences between frameworks will be, and over time, we will move from discussing framework names to thinking about which combination of framework + data flow is more appropriate.

3 summary

Recently, I combed a Web Designer made by gaea- Editor, rethinking the plug-in mechanism, and took it out to talk about it.

First of all, the react Context editor uses the DOB as a data stream and shares data with the React Context. It’s written like mobx, but that’s not the point. The plugin extension mechanism also makes heavy use of data streams.

What is the plug-in extension mechanism? Editors like VScode, for example, have great extensibility. Developers who want to add a feature can read the straightforward plug-in documentation instead of learning about the esoteric framework content, and use the plug-in to develop the desired feature. Decoupling is nice, but the key is how powerful the plug-in is, what functions, information, and capabilities the plug-in can access to the kernel?

The author’s idea is quite radical. In order to make the plug-in have the maximum power, all the kernel code of the Web Designer is written with the plug-in, except the part that calls the plug-in. So plug-ins can access and modify any data in the kernel at will, including the UI.

It’s easy to make the UI universal. Gaea-editor uses slot rendering, which means that any plug-in that provides a name can be embedded in a UI slot that declares the name, and the plug-in itself can declare any number of slots, as well as several built-in slots in the kernel. The plugin’s UI is so powerful that any UI can be replaced by a new plugin with the same name.

The remaining half is data capability. I use dependency injection to fully inject all the kernel, store and action of the plug-in into each plug-in:

@Connect
class CustomPlugin extends React.PureComponent {
  render() {
    // this.props.Actions, this.props.Stores}}Copy the code

At the same time, each plug-in can declare its own store, and the program is initialized to merge all plug-in stores into memory. So plug-ins can do almost anything, rewriting a kernel is no problem, and doing extensions is easier.

It’s a bit like webPack and other plugins:

export default (context) => {}
Copy the code

Every time you declare a plug-in, you can retrieve data from the function, so injecting data into the component through the Connect capability of data flow is also a powerful way to develop plug-ins.

More thinking

As you can see from the example of the plug-in mechanism above, data flow not only defines how data is handled and side effects are isolated, but dependency injection is also included in the list of data flow features. Front-end data flow is a very broad concept with many functions.

Redux, MOBx, and RXJS all have unique methods of data processing and side effect isolation. Meanwhile, the corresponding frameworks Redux-React, Mobx-React, and CycleJS complement various methods of dependency injection to complete the connection with the front-end framework. The combination of Redux + RXJS mobx+ RXJS is possible because they all abstract away kernel capabilities.

In the future, there will even be a framework with no data management capability, which only does the pure View layer. It is not impossible for the kernel to interconnect with Redux, MOBx and RXJS, because the data flow of the framework is too weak compared to these data flow frameworks.

The React Stateless Component is an experiment, but it’s still a bit of a niche for a view-only component that works with a data flow framework.

The pure View layer does not mean that there is no data flow management functions, such as props passthrough and update mechanism, which can be built in.

However, I believe that future frameworks may evolve towards a completely separate view from data stream, which not only fundamentally solves the framework + data stream choice debate, but also allows frameworks to focus more on the view layer.

From to

HTML5 has two interesting tags: Details and summary. By combination, details can be hidden by default. Click Summary to toggle the content under Details:

<details>
  <summary>The title</summary> 
  <p>content</p> 
</details>
Copy the code

It can also be overwritten by CSS to fully achieve the effect of collapse components.

Of course, in the case of collapse components, the open/close state of the collapse panel is controlled by the internal state of the collapse component, while the DETAILS of HTML5 only exposes CSS to developers through the internal state of the browser itself.

In the future, browsers may even provide more native supercomponents, and the internal state of components will be less and less of a concern to developers. HTML provides enough basic components that developers can simply reference CSS to change the component library. Seems like a return to the bootstrap era.

Some people say, how do you provide upper-level components that have business implications? Don’t forget about HTML Components, which can be a very nice specification when implemented with a large number of native components in the browser. DSL is no longer needed, HTML itself is a generic DSL, and frameworks are not needed, browsers have a built-in framework.

As an aside, all components are developed by HTML Components, which in a real sense realize the smooth framework. In the future, there is no need for front-end framework, no need for react to Vue mutual conversion, component loading speed is improved a level, dynamic component load may only need to load CSS dynamically. There is also no fear that components developed under different environments/frameworks will not coexist. Front-end development is always two steps forward and one step back. Don’t set a mindset. Every once in a while, you need to revisit old technologies.

Redux and Mobx would lose their advantage immediately if the details TAB of the browser implementation showed that there must be a stateful mechanism. If this stateful mechanism could be provided to developers, then the browser would probably do all the data processing, side effect isolation and dependency injection for the data stream. The greatest potential for the future is probably RXJS with its powerful pure functional data stream processing capabilities.

Of course, Redux and Mobx will still be alive and well in 2018, and even with the built-in data flow mechanism in browsers of the future, RXJS may not be suitable for large-scale teamwork, especially when there are so many non-front-end jobs working on the front end.

RXJS is likely to be used on a larger scale in more years to come when the functions of the front and back ends, and even DBAs and algorithms, converge and everyone is full stack, just as they are now with Facebook and Google.

Throughout front-end history, data flow frameworks have gone from nothing to nothing and are likely to go from there to nothing in the future. Front-end data flow frameworks are gone, but the idea of front-end data flow lives on forever and becomes ubiquitous.

4 More Discussions

The discussion address is: Close reading philosophy of Front-end Data Flow · Issue #58 · dT-fe /weekly

If you’d like to participate in the discussion, pleaseClick here to, with a new theme every week, released every Friday.