React 学习笔记 14(共享数据管理)

1.同步解决共享数据

问题引入,我最终想实现的效果如下

         

方案一:原生Redux

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './pages/Vote';
import reportWebVitals from './reportWebVitals';
import { createStore } from 'redux'

const initial = {
  title: 'React vs Vue 哪家强?',
  suppNum: 0,
  oppNum: 0
}
function reducer(state = initial, action) {
  switch (action.type) {
    case 'SUPPORT':
      state.suppNum += action.payload;
      break;
    case 'OPPOSE':
      state.oppNum += action.payload;
      break;
      default:
        break;
  }
  return state
}

const store = createStore(reducer)

ReactDOM.render(
  <React.StrictMode>
    <App store={store} />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
// vote.js
import React, { Component } from 'react'
import VoteHeader from './VoteHeader'
import VoteBody from './VoteBody'
import VoteFooter from './VoteFooter'

export default class Vote extends Component {
    render() {
        const { store } = this.props
        return (
            <div>
                <VoteHeader store={store} />
                <VoteBody store={store} />
                <VoteFooter store={store} />
            </div>
        )
    }
}
//VoteHeader.jsx
import React, { Component } from 'react'

export default class VoteHeader extends Component {
    componentDidMount(){
        const { store } = this.props;
        // 订阅事件
        store.subscribe(()=>this.forceUpdate())
    }
    render() {
        const { store } = this.props;
        const { title, suppNum, oppNum } = store.getState();
        return (
            <div>
                <h1>{title}</h1>
                <p>NUM:{suppNum + oppNum}</p>
            </div>
        )
    }
}
// VoteBody.jsx
import React, { Component } from 'react'

export default class VoteBody extends Component {
    constructor(props) {
        super(props)
        const { store } = this.props
        const { suppNum, oppNum } = store.getState()
        this.state = {
            suppNum,
            oppNum
        }
    }
    componentDidMount() {
        const { store } = this.props
        // 订阅事件
        store.subscribe(() => {
            console.log(store.getState())// {title: 'React vs Vue 哪家强?', suppNum: 0, oppNum: 0 }
            const { suppNum, oppNum } = store.getState()
            // 自己做个渲染优化吧
            if (suppNum !== this.state.suppNum) {
                this.setState({
                    suppNum: suppNum
                })
            }
            if (oppNum !== this.state.oppNum) {
                this.setState({
                    oppNum: oppNum
                })
            }
        })

    }
    render() {
        const { suppNum, oppNum } = this.state
        return (
            <div>
                <p>suppNum:{suppNum}</p>
                <p>oppNum:{oppNum}</p>
            </div>
        )
    }
}
// VoteFooter.jsx
import React, { Component } from 'react'

export default class VoteFooter extends Component {
    render() {
        return (
            <div>
                <button onClick={()=>this.handler(0)}>支持</button>
                <button onClick={()=>this.handler(1)}>反对</button>
            </div>
        )
    }
    handler = type => {
        console.log(type)
        const { store } = this.props
        if(type === 0 ){
            store.dispatch({
                type: 'SUPPORT',
                payload: 10
            })
            return
        }
        store.dispatch({
            type: 'OPPOSE',
            payload: 5
        })
    }
}

方案二:Redux工程化解决方案

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './pages/Vote';
import reportWebVitals from './reportWebVitals';
import store from './store';

ReactDOM.render(
  <React.StrictMode>
    <App store={store} />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 vote.jsx

import React, { Component } from 'react'
import VoteHeader from './VoteHeader'
import VoteBody from './VoteBody'
import VoteFooter from './VoteFooter'

export default class Vote extends Component {
    render() {
        const { store } = this.props
        return (
            <div>
                <VoteHeader store={store} />
                <VoteBody store={store} />
                <VoteFooter store={store} />
            </div>
        )
    }
}

VoteHeader.jsx

import React, { Component } from 'react'

export default class VoteHeader extends Component {
    componentDidMount(){
        const { store } = this.props;
        // 订阅事件
        store.subscribe(()=>this.forceUpdate())
    }
    render() {
        const { store } = this.props;
        // 解构时后面需要从vote模块获取
        const { title, suppNum, oppNum } = store.getState().vote;
        return (
            <div>
                <h1>{title}</h1>
                <p>NUM:{suppNum + oppNum}</p>
            </div>
        )
    }
}

VoteBody.jsx

import React, { Component } from 'react'

export default class VoteBody extends Component {
    constructor(props) {
        super(props)
        const { store } = this.props
        console.log(store.getState(),'store')
        const { suppNum, oppNum } = store.getState().vote
        this.state = {
            suppNum,
            oppNum
        }
    }
    componentDidMount() {
        const { store } = this.props
        // 订阅事件
        store.subscribe(() => {
            console.log(store.getState().vote)// {title: 'React vs Vue 哪家强?', suppNum: 0, oppNum: 0 }
            // 解构时后面需要从vote模块获取
            const { suppNum, oppNum } = store.getState().vote
            // 自己做个渲染优化吧
            if (suppNum !== this.state.suppNum) {
                this.setState({
                    suppNum: suppNum
                })
            }
            if (oppNum !== this.state.oppNum) {
                this.setState({
                    oppNum: oppNum
                })
            }
        })

    }
    render() {
        const { suppNum, oppNum } = this.state
        return (
            <div>
                <p>suppNum:{suppNum}</p>
                <p>oppNum:{oppNum}</p>
            </div>
        )
    }
}

VoteFooter.jsx

import React, { Component } from 'react'
import action from '../store/actions'

export default class VoteFooter extends Component {
    render() {
        return (
            <div>
                <button onClick={() => this.handler(0)}>支持</button>
                <button onClick={() => this.handler(1)}>反对</button>
            </div>
        )
    }
    handler = type => {
        console.log(type)
        const { store } = this.props
        if (type === 0) {
            store.dispatch(action.vote.support(10))
            return
        }
        store.dispatch(action.vote.oppose(5))
    }
}

store->actions

// voteAction.js
import * as TYPES from '../action-types'

const voteAction = {
    support(payload) {
        return {
            type: TYPES.VOTE_SUPPORT,
            payload
        }
    },
    oppose(payload) {
        return {
            type: TYPES.VOTE_OPPOSE,
            payload
        }
    }
}

export default voteAction;

// userAction.js
const userAction = {}
export default userAction;
// index.js
import voteAction from "./voteAction";
import userAction from "./userAction";


const action = {
    vote: voteAction,
    user: userAction
}

export default action;

store->reducers

//userReducer.js
const initinal = {
    title: ''
}
export default function userReducer(state = initinal, action) {
    state = JSON.parse(JSON.stringify(state))
    switch (action.type) {
        default:
            break;
    }
    return action
}
// voteReducer.js
import * as TYPES from '../action-types'
const initial = {
    title: 'React vs Vue 哪家强?',
    suppNum: 0,
    oppNum: 0
}
export default function voteReducer(state = initial, action) {
    state = JSON.parse(JSON.stringify(state))
    switch (action.type) {
        case TYPES.VOTE_SUPPORT:
            state.suppNum += action.payload;
            break;
        case TYPES.VOTE_OPPOSE:
            state.oppNum += action.payload;
            break;
        default:
            break;
    }
    return state;
}
// index.js
import { combineReducers } from "redux";
import voteReducer from "./voteReducer";
import userReducer from "./userReducer";

/**
 * 合并后的reducer
 * state:{
 *      vote:{
 *          title: ''
 *      }
 *      user:{
 *          title: ''
 *      }
 * }
 */
const reducer = combineReducers({
    vote: voteReducer,
    user: userReducer
})

export default reducer;

store->action-types

/** 宏定义 */
// vote模块
export const VOTE_SUPPORT = 'VOTE_SUPPORT';
export const VOTE_OPPOSE = 'VOTE_OPPOSE';
// user模块

store->index.js

import { createStore } from "redux";
import reducer from './reducers'


const store = createStore(reducer);

export default store;

方案三: React-Redux

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './pages/Vote';
import reportWebVitals from './reportWebVitals';
import store from './store';
import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

vote.jsx

import React, { Component } from 'react'
import VoteHeader from './VoteHeader'
import VoteBody from './VoteBody'
import VoteFooter from './VoteFooter'

export default class Vote extends Component {
    render() {
        return (
            <div>
                <VoteHeader/>
                <VoteBody/>
                <VoteFooter/>
            </div>
        )
    }
}

VoteHeader.jsx

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

class VoteHeader extends Component {
    componentDidMount(){
        // const { store } = this.props;
        // // 订阅事件
        // store.subscribe(()=>this.forceUpdate())
    }
    render() {
        // 解构时后面需要从vote模块获取
        console.log(this.props)
        const { title, suppNum, oppNum } = this.props;
        return (
            <div>
                <h1>{title}</h1>
                <p>NUM:{suppNum + oppNum}</p>
            </div>
        )
    }
}
const mapStateToProps =(state)=>{
    console.log(state)// {vote:{...},user:{...}}
    return {
        ...state.vote
    }
}
export default connect(mapStateToProps)(VoteHeader)

VoteBody.jsx

import React, { Component } from 'react'
import { connect } from 'react-redux'

class VoteBody extends Component {
    // constructor(props) {
    //     super(props)
    //     const { store } = this.props
    //     console.log(store.getState(),'store')
    //     const { suppNum, oppNum } = store.getState().vote
    //     this.state = {
    //         suppNum,
    //         oppNum
    //     }
    // }
    // componentDidMount() {
    //     const { store } = this.props
    //     // 订阅事件
    //     store.subscribe(() => {
    //         console.log(store.getState().vote)// {title: 'React vs Vue 哪家强?', suppNum: 0, oppNum: 0 }
    //         // 解构时后面需要从vote模块获取
    //         const { suppNum, oppNum } = store.getState().vote
    //         // 自己做个渲染优化吧
    //         if (suppNum !== this.state.suppNum) {
    //             this.setState({
    //                 suppNum: suppNum
    //             })
    //         }
    //         if (oppNum !== this.state.oppNum) {
    //             this.setState({
    //                 oppNum: oppNum
    //             })
    //         }
    //     })

    // }
    render() {
        const { suppNum, oppNum } = this.props
        return (
            <div>
                <p>suppNum:{suppNum}</p>
                <p>oppNum:{oppNum}</p>
            </div>
        )
    }
}
export default connect(state=>state.vote)(VoteBody);

VoteFooter.jsx

import React, { Component } from 'react'
import { connect } from 'react-redux'
import action from '../store/actions'
class VoteFooter extends Component {
    render() {
        return (
            <div>
                <button onClick={() => this.handler(0)}>支持</button>
                <button onClick={() => this.handler(1)}>反对</button>
            </div>
        )
    }
    handler = type => {
        const { support, oppose } = this.props
        if (type === 0) {
            support(10)
            return
        }
        oppose(5)
    }
}
// 函数形式
// const mapDispatchToProps = dispatch => {
//     return {
//         support(payload) {
//             dispatch(action.vote.support(payload))
//         },
//         oppose(payload) {
//             dispatch(action.vote.oppose(payload))
//         }
//     }
// }
// 对象形式
// action.vote= {
//     support(payload) {
//         return {
//             type: TYPES.VOTE_SUPPORT,
//             payload
//         }
//     },
//     oppose(payload) {
//         return {
//             type: TYPES.VOTE_OPPOSE,
//             payload
//         }
//     }
// }
export default connect(null, action.vote)(VoteFooter);

store文件夹下的内容和方案二相同,不再赘述。

2.异步解决方法

问题引入,假设现在我们点解投票之后,并不是马上修改值,而是延时1秒之后,才更新值。此时我们就要引入中间件来解决

方案一 rudux-thunk

store/index.js

import { createStore,applyMiddleware } from "redux";
import logger from "redux-logger";
import thunk from "redux-thunk"
import reducer from './reducers'


const store = createStore(reducer,applyMiddleware(logger,thunk));

export default store;

store/actions/voteAction.js

import * as TYPES from '../action-types'

const voteAction = {
    support(payload) {
        // setTimeout(() => {
        //     return {
        //         type: TYPES.VOTE_SUPPORT,
        //         payload
        //     }
        // }, 1000)
        // redux-thunk中间件的使用
        return dispatch => {
            setTimeout(() => {
                dispatch(
                    {
                        type: TYPES.VOTE_SUPPORT,
                        payload
                    }
                )

            }, 1000)
        }

    },
    oppose(payload) {
        return {
            type: TYPES.VOTE_OPPOSE,
            payload
        }
    }
}

export default voteAction;

方案二 rudex-promise

store/index.js

import { createStore,applyMiddleware } from "redux";
import logger from "redux-logger";
import thunk from "redux-thunk"
import promise from "redux-promise";
import reducer from './reducers'


const store = createStore(reducer,applyMiddleware(logger,thunk,promise));

export default store;

store/actions/voteAction.js

import * as TYPES from '../action-types'

const voteAction = {
    support(payload) {
        // setTimeout(() => {
        //     return {
        //         type: TYPES.VOTE_SUPPORT,
        //         payload
        //     }
        // }, 1000)
        // redux-thunk中间件的使用
        // return dispatch => {
        //     setTimeout(() => {
        //         dispatch(
        //             {
        //                 type: TYPES.VOTE_SUPPORT,
        //                 payload
        //             }
        //         )

        //     }, 1000)
        // }
        // redux-promise中间件的使用,返回的负荷属性必须用payload,用其他的属性不好用
        return {
            type: TYPES.VOTE_SUPPORT,
            payload: new Promise((resolve, reject) => {
                setTimeout(_ => {
                    resolve(payload)
                }, 1000)
            })
        }

    },
    oppose(payload) {
        return {
            type: TYPES.VOTE_OPPOSE,
            payload
        }
    }
}

export default voteAction;

方案三 redux-saga

store/index.js

import { createStore,applyMiddleware } from "redux";
import logger from "redux-logger";
import thunk from "redux-thunk"
import promise from "redux-promise";
import reducer from './reducers'


// redux-saga
import createSagaMiddleware from "redux-saga";
// 引入根saga
import rootSaga from './saga/rootSaga';
// 创建一个saga中间件
const sagaMiddleware = createSagaMiddleware()


const store = createStore(reducer,applyMiddleware(logger,thunk,promise,sagaMiddleware));

// 动态执行saga,run函数需要在store创建之后调用
sagaMiddleware.run(rootSaga)

export default store;

saga/rootSage.js

import { call, put,takeEvery } from "redux-saga/effects";
import * as TYPES from '../action-types'
import actions from "../actions";

// const delay = function (ms) {
//     return new Promise((resolve, reject) => {
//       setTimeout(() => {
//         resolve(30)
//       }, ms)
//     })
//   }
export const delay = ms => new Promise((resolve, reject) => setTimeout(() => {
    resolve(30)
}, ms))
/**
* 通过action 接收传递的参数
*/
function* asyncSaga(action) {
    const data = yield call(delay, 3000);
    console.log(action,data)
    // yield put({ type: TYPES.VOTE_SUPPORT, payload: data })
    yield put(actions.vote.support(action.payload))
}

export default function* rootSaga() {
    console.log('启动saga')
    yield takeEvery(TYPES.VOTE_ASYNC, asyncSaga)
}

action-types.js

/** 宏定义 */
// vote模块
export const VOTE_SUPPORT = 'VOTE_SUPPORT';
export const VOTE_OPPOSE = 'VOTE_OPPOSE';
// 异步saga
export const VOTE_ASYNC = 'VOTE_ASYNC';
// user模块

voteAction.js

import * as TYPES from '../action-types'

const voteAction = {
    support(payload) {
        // setTimeout(() => {
        //     return {
        //         type: TYPES.VOTE_SUPPORT,
        //         payload
        //     }
        // }, 1000)
        // redux-thunk中间件的使用
        // return dispatch => {
        //     setTimeout(() => {
        //         dispatch(
        //             {
        //                 type: TYPES.VOTE_SUPPORT,
        //                 payload
        //             }
        //         )

        //     }, 1000)
        // }
        // redux-promise中间件的使用,返回的负荷属性必须用payload,用其他的属性不好用
        // return {
        //     type: TYPES.VOTE_SUPPORT,
        //     payload: new Promise((resolve, reject) => {
        //         setTimeout(_ => {
        //             resolve(payload)
        //         }, 1000)
        //     })
        // }
        return {
            type: TYPES.VOTE_SUPPORT,
            payload
        }

    },
    oppose(payload) {
        return {
            type: TYPES.VOTE_OPPOSE,
            payload
        }
    },
    asyncSupport(payload) {
        return {
            type: TYPES.VOTE_ASYNC,
            payload
        }
    }
}

export default voteAction;

VoteFooter.jsx

import React, { Component } from 'react'
import { connect } from 'react-redux'
import action from '../store/actions'
class VoteFooter extends Component {
    render() {
        const { support, oppose, asyncSupport } = this.props
        return (
            <div>
                <button onClick={() => support(10)}>支持</button>
                <button onClick={() => oppose(5)}>反对</button>
                // 测试saga 并传递参数
                <button onClick={() => asyncSupport(20)}>异步支持</button>
            </div>
        )
    }
    handler = type => {
        const { support, oppose } = this.props
        if (type === 0) {
            support(10)
            return
        }
        oppose(5)
    }
}
// 函数形式
// const mapDispatchToProps = dispatch => {
//     return {
//         support(payload) {
//             dispatch(action.vote.support(payload))
//         },
//         oppose(payload) {
//             dispatch(action.vote.oppose(payload))
//         }
//     }
// }
// 对象形式
// action.vote= {
//     support(payload) {
//         return {
//             type: TYPES.VOTE_SUPPORT,
//             payload
//         }
//     },
//     oppose(payload) {
//         return {
//             type: TYPES.VOTE_OPPOSE,
//             payload
//         }
//     }
// }
export default connect(null, action.vote)(VoteFooter);

至此 数据共享的异步和同步方案全部分享完毕,有不妥之处还请见谅。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值