redux和mobx入门使用

项目基础脚手架使用 create-react-app 生成,新建三个文件夹,组件集components, 页面集 pages, 以及状态管理集 store。
1.App.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 {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();

引入页面Foo, Bar,路由 react-router-dom插件,以及状态管理 react-redux。状态统一管理 store/index.js,这里统一管理store。
通过Provider 传入 store,包裹所有组件,这样组件内部能拿到store数据。

注意
这里的 Switch组件,当匹配到一个路由的时候,就不用往下匹配,这个也是项目优化的一个部分。

2.store 处理
store
├── index.js
└── reducer.js

index.js
我这里演示的是一个reducer,如果是多个reducer 可以用 combineReducers 进行合并

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

定义简单的action
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.页面路由 bar.js
import React from ‘react’;
import { connect } from ‘react-redux’;

// 组件B中获取count的值 
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;

使用redux中 connect 将组件和store链接起来。connect 一共四个参数,可以看这个文章connect,这个组件里 我们只用里第一个参数,将store 中的值 传递给组件,这样 Bar 函数组件props里面就有我们传进来的数据。

4.页面路由 foo.js
import React, {useState, useEffect} from ‘react’;
import { connect } from ‘react-redux’
// 组件B中获取count的值
// http://localhost:4000/get/alluser 接口地址
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

注意

这里的connect 第一个参数,跟上面的例子差不多,返回的是state 里面一个具体的值,这样可以控制页面组件里的具体数据。
HOOK 组件 使用useEffect 调用接口,获取数据,渲染页面。对于HOOK的使用 不是我们这节的重点,具体学习可以查看react-hook
5.组件 commentA.js
注意,重点

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>组件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 页面</Link></li>
            <li><Link to="/bar">Bar 页面</Link></li>
            <li><Link to="/">APP 主页面</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

connect 第一个参数,因为不需要,我们没有传store进组件,第二个函数参数mapDispatchToProps,我们传递了一些action方法进去,这些方法会绑定到组件当中。
我们知道我们不能直接修改store 里面的数据,我们需要通过派发器(dispatch)派发一个动作(action),这也是唯一修改state的方法,
这个action方法会触发我们的reducer方法 ,根据对应的action,返回对应的state。

6.组件 comnentB.js
通过上面 componentA的操作,我们已经修改了state 值,在componentB 中就体现出来了,代码如下

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

// 组件B中获取count的值 
function CompnentB(props) {
    const { count } = props
    return <div>
        <h2>组件B</h2>
        <p>count: {count}</p>
    </div>
}

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

export default CompnentBB

整体效果,图片如下
redux-demo

以上是redux 部分的demo,我们继续使用mobx,整个项目复制一遍,我们修改下数据管理部分和页面使用状态数据部分,其他层级不变,开始的项目结构可以看出。
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();

这里主要是将redux 的Provider 替换成 mobx的Provider

  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() {
// 添加makeObservable mobx6.0 状态数据已经修改,但是页面没有更新,需要通过这个方法来强制更新数据
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.componentA 组件使用
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>组件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 页面</Link></li>
            <li><Link to="/bar">Bar 页面</Link></li>
            <li><Link to="/">APP 主页面</Link></li>
        </ul>
    </div>
}

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

inject(‘store’)(observer(CompnentA)) => 可以理解为将store 注入 可监测的 CompnentA 中。

点击事件方法 addCount 它会触发 store 里面的 action 方法,

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

action 方法 修改 state上的数据,页面上的数据会及时刷新。

从这里我们就可以明显看出与redux的不同,不需要通过reducer 去根据不同的type 来修改state 上的数据,而是直接通过action方法直接修改。

4.其他页面使用mobx的姿势
export default inject(‘store’)(observer(Bar)); => 可以理解为将store 注入 可监测的 页面 Bar 中。

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

// 组件B中获取count的值 
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. create-react-app 生成的脚手架不支持@ 装饰器语法的方案。
    package.json 修改启动命令
    “scripts”: {
    “start”: “PORT=8000 react-app-rewired start”,
    “build”: “react-app-rewired build”,
    “test”: “react-app-rewired test”,
    “eject”: “react-app-rewired eject”
    },
    安装插件,
    npm install customize-cra react-app-rewired @babel/plugin-proposal-decorators --save

在src下 新建文件 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/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

上一篇:再见,Flutter自带状态管理!你好,MobX库


下一篇:Java 对象是否GC回收