preface

React, VUE, and other popular front-end frameworks are also relatively complete. For large-scale projects, reasonable organization of data management is inseparable to the overall quality of the project and development efficiency, such as

  • vue: vuex
  • React: Redux, MOBx (V4/5, v6), Recoil

I will not compare Redux in detail here. Personally, THERE are several reasons not to choose Redux

  • Redux: Redux Hooks already implement React Hooks, useReducer and useContext are not necessary
  • Importantly, the Redux data flow mechanism is top-down, inconsistent with the current popular “plug and play” design principles, and has higher development costs than Mobx and Recoil (except umi and DVA, which have some limitations due to higher umi learning and maintenance costs and less flexible DVA).

The overall contrast

  • Mobxjs/mobx (6) : github.com/mobxjs/mobx
  • Facebook/Recoil: github.com/facebookexp…
Compare the item mobx recoil
Lot number of Star 23.1 k. 11.4 k.
The React hooks to support mobx v6 + mobx-react

– Mobx is an observable data object tool that can be used in React, Vue, and JS projects

– Mobx-react is a tool to associate observables with react
No additional auxiliary tools, natural support
UI and logic are decoupled support

– React calls the store action, and the logic is processed in the store
Does not support

– React calls Recoil’s useRecoilState API to implement business logic in components, such as:

const [amount, setAmount] = useRecoilState(amountState)
Singletons versus multiple cases – export default new Store() is instantiated internally

– export default Store, which is instantiated at the reference point

Through the program control, more flexible, easy to customize
Each atom and each selector is a singleton
Data Flow (single project) – globalStore => Root => React.FC

– pageStore => React.FC
atom[ => selector] => React.FC
State induction The when, reaction Does not support
The interaction between the store support Does not support
Number of common apis (PCS) 5 + 6 +
Learning costs The lower The lower
Understand the cost low In the
Development experience friendly Average, even troublesome, not suitable for large projects

Basic service contrast

mobx

  • TestStore, for example
import { makeAutoObservable, runInAction } from 'mobx';

class TestStore {
  amount = 1; // observable state
  data; // observable state

  constructor() {
    // Automatically listen on all attributes
    makeAutoObservable(this);
  }
  
  // computed
  get price() :string {
    return ` $The ${this.amount * 100}`;
  }
  
  // action
  increment(): void {
    this.amount++;
  }
  
  / / async action,
  async asyncAction(id: string) :Promise<void> {
    try {
      const data = await geAsyncData(id);
      // In an asynchronous action, the code contains the runInAction(() => {/**... * /})
      runInAction(() = > {
        this.data = data;
      });
    } catch (e) {
      throw new Error(e); }}}export default new TestStore();
Copy the code
  • Use In React: Use mobx-React
import { FC } from 'react';
import { observer } from 'mobx-react';
import store from './testStore';

const Test: FC = () = > {
  return (
    <div>
      <div>count: {store.amount}</div>
      <div>price: {store.price}</div>
      <button type="button" onClick={()= > store.increment()}>add +1</button>
      <button type="button" onClick={()= >Store. AsyncAction (1)}> Async request</button>
    </div>
  );
};

/ / listening Component
export default observer(Test);
Copy the code

recoil

  • Recoil’s data is all particles, paved,
import { atom, selector } from 'recoil';

// state
export const amountState = atom({
  key: 'amountState'.default: 0});// computed
export const priceState = selector({
  key: 'priceState'.get: ({ get }) = > {
    return ` $${get(amountState) * 100}`; ; }});// async state request
export const asyncTestData = selector({
  key: 'asyncTestData'.get: async ({ get }) => {
    return awaitgeAsyncData(); }});// What's the fuck, if you want async data with params in recoil-store, you must use another API "selectorFamily"

// async state request with params
export const asyncTestDataWithParams = selectorFamily({
  key: 'asyncTestDataWithParams'.get: id= > async ({ get }) => {
    return awaitgeAsyncData(id); }});Copy the code
  • Use In React
import { FC } from 'react'; import { useRecoilState, useRecoilValue } from 'mobx-react'; import { amountState, priceState, asyncTestDataWithParams } from './testStore'; const Test: FC = () => { const [amount, setAmount] = useRecoilState(amountState); const price = useRecoilValue(priceState); const getData = () => { return userRecoilValue(asyncTestDataWithParams(1)); } return ( <div> <div>count: {amount}</div> <div>price: {price}</div> <button type="button" onClick={() => setAmount(amount + 1)}>add +1</button> <button type="button" The onClick = {() = > getData ()} > asynchronous request < / button > < / div >). }; // Monitor Component export default Observer (Test);Copy the code

State induction

  • State sensing: When a certain observable data of AStore reaches the condition, it will automatically trigger other actions of the store or trigger actions of other stores. The program description is when(a.isready === true) => B.action().
  • The Recoil particle says no such scenario exists
  • Mobx supports status-sensing scenarios
class TestStore {
  isReady = false;
  count = 0;

  constructor() {
    makeAutoObservable(this);
    // listen for isReady, and when isReady becomes true, doSomething (one-time behavior)
    when(() = this.isReady, () = > this.doSomething());
    // Listen for amount, and output value, previousValue after each amount change
    reaction(
      () = > this.amount,
      (value, previousValue) = > {
        console.log(value, previousValue); }); } doReady():void {
    this.isReady = true;
  }
  
  doSomething(): void{... } increment():void {
    this.amount++; }}Copy the code

The interaction between the Store

  • Recoil: Not supported
  • Mobx: Singleton mode based on store instances, and stores can reference and call each other, and initial control of data flow can be achieved through stores
import stores from './installStores';
class ScheduleStore {
  isRunning = false;
  constructor() {
    makeAutoObservable(this);
  }
  async run(): Promise<void> {
    try {
      // User information is initialized
      await stores.userStore.init();
      await stores.testStore.init();
      runInAction(() = > {
        this.isRunning = true;
      });
    } catch (e) {
      console.log(e); }}}Copy the code

Store the form

  • Mobx: A store as a class, easy to extend functionality: inherit classes, implement interfaces
  • Recoli: a single particle store, not extensible, to carry on advanced usage

The end of the

Mobx and Recoil basic comparative analysis has been OK, in short, each has its own characteristics, are very excellent data management tools, in the selection of technology, also need to refer to the actual application scenarios and development costs of the project, I hope this article can help you all.

To learn more about MOBx, read React hooks + Mobx Usage of Summary

reference

  • mobx.js.org/
  • mobx-react.js.org/

Join us at ❤️

Bytedance Xinfoli team

Nice Leader: Senior technical expert, well-known gold digger columnist, founder of Flutter Chinese community, founder of Flutter Chinese community open source project, well-known developer of Github community, author of dio, FLY, dsBridge and other well-known open source projects

We look forward to your joining us to change our lives with technology!!

Recruitment link: job.toutiao.com/s/JHjRX8B