If you are thirsty for talents, please reserve this part of the content and indicate the source.
Mobx and Redux are used to manage data state in React.
-
Passing of parent and child components
-
Passing between sibling components
-
Pass between components across hierarchies
In summary, there are many excellent solutions in the community such as Redux and MOBx for state sharing in these situations. Generally speaking, Redux is a well-designed, rigorously unidirectional data flow framework suitable for large projects. Mobx is a more flexible data layer framework for small and medium sized applications.
Principle:
Before we get to the principles, we might want to review the observer model, the decorator model
Observer model
You might think of the common jQuery on, window.addEventListener, which is a publish/subscribe mode (observer mode with event channels), specific code
-
Partitioning the system into a series of classes that work together,
-
Reduces tight class coupling
-
A target has an arbitrary number of dependent observers who are notified whenever the state of the target changes
Decorator pattern
Check out Ruan’s book on the simplest ES7 decorator to implement decorator mode. Note that decorators can only be used for classes and their methods
Begin to introduce
Let’s take a look at mobx with a simple example
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import { observable, autorun } from "mobx";
const counter = observable({
count: 0
});
window.counter = counter;
autorun(() => {
console.log("#count", counter.count);
});
function App() {
return (
<div className="App">
<h1>Hello mobx</h1>
<button
onClick={e => {
counter.count++;
}}
>
click +1
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Copy the code
-
Execute the incoming function to calculate observing
- How do you calculate that? Access to data goes to the Get () method of the Observable, which records data
-
Add the Derivation to the Observer of Observables
At this point, the dependency relationship between Observable and Derivation is established. How does counter. Set () trigger autorun autoexecution? With the above layer of dependencies, this is easy to understand. The counter.set() implementation takes dependencies from its observing property and triggers their re-execution.
Runtime depends on computation
Let’s do another example.
import { observable, autorun } from 'mobx'; const counter = observable(0); const foo = observable(0); const bar = observable(0); autorun(() => { if (counter.get() === 0) { console.log('foo', foo.get()); } else { console.log('bar', bar.get()); }}); bar.set(10); // does not trigger autorun counter.set(1); // Trigger autorun foo.set(100); // Do not trigger autorun bar.set(100); / / triggers the autorunCopy the code
Execution Result:
foo 0
bar 10
bar 100
Copy the code
Autorun relies on counter and foo, and then when counter is set to 1, it doesn’t rely on Foo, it relies on counter and bar. So modifying foo later does not trigger Autorun. So how does Mobx calculate dependencies at run time? In fact, the previous Autorun execution steps are simplified, the real thing is this:
-
Generate a Derivation
-
Record oldObserving (+)
-
Execute the incoming function to calculate observing
- How do you calculate that? Access to data goes to the Get () method of the Observable, which records data
-
Diff and oldObserving to get new and deleted lists (+)
-
Modify observables using the previous diff results
Diff logic is added to dynamically update the dependency table every time it is executed.
get/set magic
Counter = appState.counter = counter get = counter. Set = appState.counter = appState.counter = appState.counter = appState.counter This is all about data types. Mobx supports Primitives, Arrays, classes, and Objects. Primitives can only be valued and set using the set and get methods. For Object, you can customize getters and setters using the Object.defineProperty method.
Object.defineProperty(adm.target, propName, {
get: function() { return observable.get(); },
set: ...
});
Copy the code
See the source code.
ComputedValue
ComputedValue implements the interface of both Observable and Derivation, that is, it can listen to an Observable and be listened to by Derivation.
Reaction
Reaction is inherently Derivation, but it can no longer be listened to by other scales.
Autorun
Autorun is a simple encapsulation of Reaction.
Synchronous execution
Other TFRP libraries, such as Tracker and Knockout, execute data updates asynchronously, waiting for the next event loop. (think of it as setTimeout.) Mobx execution is synchronous, which has two benefits:
-
A ComputedValue can be used immediately after its dependent value is modified, so that you never use an out-of-date ComputedValue
-
Easy to debug, no redundant Promise/Async libraries in the stack
Transation
Because mobx updates are synchronous, reaction updates are triggered each time a value is set. So in order to batch update, transation was introduced.
transaction(() => {
user.firstName = "foo";
user.lastName = "bar";
});
Copy the code
"babel": {
"plugins": [
"transform-decorators-legacy"
],
"presets": [
"react-app"
]
},
Copy the code
You can also use Mobx without decorators, see here
Application:
See cn.mobx.js.org/ apis used in the project in more detail: codesandbox. IO/s/mobxjutid…
import { observable } from "mobx";
import { observer } from "mobx-react";
import React, { Component } from "react";
import ReactDOM from "react-dom";
export const store = observable({
count: 0
});
store.increment = function() {
this.count++;
};
store.decrement = function() {
this.count--;
};
@observer
class Count extends Component {
render() {
return (
<div>
Counter: {store.count} <br />
<button onClick={this.handleInc}> + </button>
<button onClick={this.handleDec}> - </button>
</div>
);
}
handleInc() {
store.increment();
}
handleDec() {
store.decrement();
}
}
ReactDOM.render(<Count />, document.querySelector("#root"));
Copy the code
Mobx defines store, and the render execution of Count refers to store data. Then if the user clicks the + or – button, it will trigger the store modification, and the store modification will automatically trigger the Counter update. A store is a shared data state that can be used for multiple applications
An example of mobx implementing Todo
Mobx vs. Redux
-
In Redux’s view, data consistency is very important. In order to maintain data consistency, data in stores should be formalized as much as possible, that is, to reduce all unnecessary redundancy. In order to limit data modification, data in stores should be Immutable. The Reducer can only be triggered by action to update the Store.
-
Mobx agrees that data consistency is important, but it believes that the fundamental solution to the problem is not to formalize data, but to not give it the opportunity to become inconsistent. As a result, Mobx encourages data to be “de-canonized,” and redundancy is fine. As long as all data is linked and the data that depends on it is updated automatically, data inconsistencies will not occur.
Although one of Mobx’s initial selling points was to modify data directly, in practice this was found to be disorganized and undisciplined, so Mobx later introduced the concept of Action. Unlike Redux’s Actions, actions in Mobx are a function that doesn’t dispatch and changes data when called. In the code above, Increment and Decrement are actions.
To force action, don’t modify Observable data directly. Use Mobx configure as follows:
import {configure} from 'mobx';
configure({enforceActions: true});
Copy the code
To summarize the differences between Redux and Mobx, including these aspects:
-
Redux encourages one Store for an app, while Mobx encourages multiple stores.
-
Redux uses pull to use data, which is consistent with React, but Mobx uses push to use data, which is closer to tools like RxJS.
-
While Redux encourages data formalization and reduces redundancy, Mobx allows data redundancy but still keeps data consistent.
Extension: Functional programming
- www.zhihu.com/question/28…
- Byvoid. Making. IO/slides TAB/apio…
Reference:
- cn.mobx.js.org/
- Github.com/sorrycc/blo…
- Medium.com/hackernoon/…
- Juejin. Cn/book / 5 ba428…
- Github.com/sorrycc/blo…