Getting started with redux and mobx

Posted by amit on Fri, 11 Feb 2022 07:50:53 +0100

The basic scaffold of the project is generated using create react app, and three folders are created, including component set components, page set pages, and state management set store.
1.App.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import reportWebVitals from './reportWebVitals';
import App from './App';
//Add the following code
import Foo from './pages/foo';
import Bar from './pages/bar';
import {HashRouter, Route, Switch } from 'react-router-dom'
import {Provider} from 'react-redux';
import store from './store/index'
ReactDOM.render(

<React.StrictMode>

redux-demo









</React.StrictMode>
,
document.getElementById('root')
);
reportWebVitals();

Introduce page Foo, Bar, route react router DOM plug-in, and state management react redux. Unified state management / index.store JS, where the store is managed uniformly.
Pass in the store through the Provider and wrap all components so that the store data can be obtained inside the component.

be careful
When the Switch component here matches a route, it does not need to match down. This is also a part of project optimization.

2.store processing
store
├── index.js
└── reducer.js

index.js
What I'm demonstrating here is a reducer. If there are multiple reducers, you can combine them with combineReducers

import { createStore } from 'redux';
import reducer from './reducer';
export default createStore(reducer)

Define simple action s
reducer.js

const defaultState = {
    count: 1,
    pageName: "default page"
}

const Store = (state = defaultState, action) => {
    switch(action.type) {
        case 'COUNT_ADD':
            state.count += action.value;
            break;
        case 'COUNT_SUB':
            state.count -= action.value;
            break;
        case 'COUNT_MUTIL':
            state.count *= action.value;
            break;
        default:
            state.count = defaultState.count;
    }

    return {
        ...state
    }
}

export default  Store

3. Page routing bar js
import React from 'react';
import { connect } from 'react-redux';

// Get the value of count in component B 
function Bar(props) {
    const { count, pageName} = props
    return <div>
        <h2>Bar</h2>
        <p>count: {count}</p>
        <p>pageName: {pageName}</p>
    </div>
}

const BarPage = connect(state => (
    state
))(Bar)

export default BarPage;

Use connect in redux to link components and stores. Connect has four parameters in total. You can see this article connect. In this component, we only use the first parameter to pass the value in the store to the component, so that the Bar function component props has the data we passed in.

4. Page routing foo js
import React, {useState, useEffect} from 'react';
import { connect } from 'react-redux'
//Get the value of count in component B
// http://localhost:4000/get/alluser Interface address
const Foo = (props) => {
const { count } = props
const [ allData, setAllData ] = useState([]);
useEffect(()=>{
fetch("http://localhost:4000/get/alluser").then(res => {
res.json().then(data => {
setAllData(data.users)
})
})
},[])

    return <div>
        <h2>Foo</h2>
        <p>count: {count}</p>
        <ul>
            {allData.map((item,index)=>{
                return <li key={index}>
                    <p>{item.name}</p>
                    <img src={item.avatar_url} width="180"/>
                </li>
            })}
        </ul>
    </div>
}

const FooPage = connect(state => (
    {
        count: state.count
    }
))(Foo)

export default  FooPage

be careful

The first connect parameter here, similar to the above example, returns a specific value in state, which can control the specific data in the page component.
The HOOK component uses useEffect to call the interface to obtain data and render the page. The use of HOOK is not the focus of this section. You can check react HOOK for specific learning
5. Component commenta js
Attention, focus

import React from 'react';
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'

const CompnentA = (props) => {
    // const [count, SetCount] = useState(props.count)
    const addCount = () => {
        const  { changeCount } = props;
        changeCount({
            type: "COUNT_ADD",
            value: 3,
        })
    }
    const subCount = () => {
        const  { changeCount } = props;
        changeCount({
            type: "COUNT_SUB",
            value: 1,
        })
    }
    const mutilCountfun = () => {
        const {mutilCount} = props;
        mutilCount({
            type: 'COUNT_MUTIL',
            value: 10
        })
    }
    return <div>
        <h2>assembly A</h2>
        <p><button onClick={addCount}>count +3</button></p>
        <p><button onClick={subCount}>count -1</button></p>
        <p><button onClick={mutilCountfun}>count * 10</button></p>
        <ul>
            <li><Link to="/foo">Foo page</Link></li>
            <li><Link to="/bar">Bar page</Link></li>
            <li><Link to="/">APP Main page</Link></li>
        </ul>
    </div>
}

const Compnent = connect(null, dispatch => ({
    changeCount: ({type, value}) => dispatch({
        type,
        value, 
    }),
    mutilCount: ({type, value}) => dispatch({
        type,
        value
    })
}))(CompnentA)

export default Compnent

The first parameter of connect is unnecessary. We did not pass the store into the component. The second function parameter mapDispatchToProps, we passed some action methods into it, and these methods will be bound to the component.
We know that we cannot directly modify the data in the store. We need to dispatch an action through the dispatcher, which is also the only way to modify the state,
This action method will trigger our reducer method to return the corresponding state according to the corresponding action.

6. Component comnentb js
Through the above operation of componentA, we have modified the state value, which is reflected in componentB. The code is as follows

import React  from 'react';
import { connect } from 'react-redux'

// Get the value of count in component B 
function CompnentB(props) {
    const { count } = props
    return <div>
        <h2>assembly B</h2>
        <p>count: {count}</p>
    </div>
}

const CompnentBB = connect(state => (
    {
        count: state.count
    }
))(CompnentB)

export default CompnentBB

The overall effect is shown below
redux-demo

The above is the demo of the redux part. We continue to use mobx and copy the whole project. We modify the data management part and the page usage status data part. Other levels remain unchanged, and the starting project structure can be seen.
mobx-demo

  1. index.js
    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import reportWebVitals from './reportWebVitals';

    import App from './App';
    import Foo from './pages/foo';
    import Bar from './pages/bar';
    import { configure } from "mobx";
    import { Provider } from "mobx-react";
    import store from './store/index'
    import {HashRouter, Route, Switch } from 'react-router-dom'
    configure({ enforceActions: "observed" });
    ReactDOM.render(

    <React.StrictMode>

    mobx-demo









    </React.StrictMode>
    ,
    document.getElementById('root')
    );

    reportWebVitals();

The main purpose here is to replace the Provider of redux with the Provider of mobx

  1. store/index
    store
    ├── index.js
    └── storeone.js

index.js
import StoreOne from "./storeone";
class Store {
constructor() {
this.storeOne = StoreOne;
}
}
export default new Store();
storeone.js
import { observable, action, makeObservable } from 'mobx';
class appStore {
constructor() {
//Add makeobservable mobx6 0 status data has been modified, but the page has not been updated. This method needs to be used to force the data to be updated
makeObservable(this)
}
// state
@observable count = 1;
@observable pageName = "default pageName";

    // getter
    get skinWindow() {
        return {
        };
    }

    // action
    @action
    addCount(payload) {
        this.count += payload;
    }
    @action
    subCount(payload) {
        this.count -= payload;
    }

    @action
    mutilCountfun(payload) {
        this.count *= payload;
    }
}
const as = new appStore();
export default as

3. Use of ComponentA components
import React from 'react';
import { Link } from 'react-router-dom'
import { observer, inject } from 'mobx-react';

const CompnentA = (props) => {
    const {storeOne} =  props.store
    const addCount = () => {
        storeOne.addCount(3)
    }
    const subCount = () => {
        storeOne.subCount(1)
    }
    const mutilCountfun = () => {
        storeOne.mutilCountfun(10)
    }
    return <div>
        <h2>assembly A</h2>
        <p><button onClick={addCount}>count +3</button></p>
        <p><button onClick={subCount}>count -1</button></p>
        <p><button onClick={mutilCountfun}>count * 10</button></p>
        <ul>
            <li><Link to="/foo">Foo page</Link></li>
            <li><Link to="/bar">Bar page</Link></li>
            <li><Link to="/">APP Main page</Link></li>
        </ul>
    </div>
}

export default inject('store')(observer(CompnentA));

inject('store ') (observer (ComponentA)) = > can be understood as injecting the store into the monitorable ComponentA.

Click the event method addCount, which will trigger the action method in the store,

addCount(payload) {
    this.count += payload;
}

The action method modifies the data on the state, and the data on the page will be refreshed in time.

From here, we can clearly see that different from redux, it is not necessary to modify the data on the state according to different type s through reducer, but directly through the action method.

4. Use mobx pose on other pages
export default inject(‘store’)(observer(Bar)); => It can be understood as injecting the store into the monitorable page bar.

import React  from 'react';
import { inject, observer } from 'mobx-react';

// Get the value of count in component B 
function Bar(props) {
    const { count, pageName} = props.store.storeOne
    return <div>
        <h2>Bar</h2>
        <p>count: {count}</p>
        <p>pageName: {pageName}</p>
    </div>
}

export default inject('store')(observer(Bar));
  1. The scaffold generated by create react app does not support the scheme of @ decorator syntax.
    package.json modify startup command
    "scripts": {
    "start": "PORT=8000 react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
    },
    Install plug-ins,
    npm install customize-cra react-app-rewired @babel/plugin-proposal-decorators --save

Under src, create a new file config overrides js
const{override,addDecoratorsLegacy}=require('customize-cra');
module.exports=override(addDecoratorsLegacy());
USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
Amazon evaluation www.yisuping.com cn
Shenzhen website construction www.sz886.com com