美文网首页
React:Redux进阶

React:Redux进阶

作者: SwiftBirds | 来源:发表于2019-07-26 16:09 被阅读0次

    问题引入

    描述

    上次使用Redux,最终实现了兄弟组件之间的通信--点击左边的导航栏(左边蓝色部分),右边的头部(红色部分)会改变成对应的文字。

    问题1.PNG

    之后又用Redux,准备实现该界面(订单管理)的另一个功能--选中表格中的一栏,点击上面的详细页面按钮(第二个蓝色按钮),可以打开一个新页面,并在该页面上显示选中表格栏的信息。这是一个跨页面的状态通信。点击详细页面按钮的事件代码如下:

    openInfoPage = () => {
        //如果未选中一条表格栏,弹窗警告
        if (!this.state.selectedItem) {
            Modal.info({
                title: '信息',
                content: '请先选择一条订单'
            })
            return;
        }
        //将选中的表格栏信息传入Redux的store状态中
        this.props.dispatch(orderSelect(this.state.selectedItem))
        //设置路由,跳转新页面--(默认打开新窗口;传入参数'_self'则会在本页面打开新页面,此过程只是单存的路由跳转)
        window.open(`/#/order/detail/${this.state.selectedItem.id}`,'_self')
    }
    

    在实际操作中,若给新打开的页面传入一个'_self'参数,新页面是在目前的页面打开,很幸运,他能完成既定的目标。

    问题2.PNG

    但若是传入参数'_blank'或者不传参,则会单独打开一个新页面。很不幸的是,新页面显示的是store状态的初始值。


    问题4.PNG

    分析

    造成这个现象的原因是:

    • _self 只是单纯的路由跳转,更换一个新的组件(该组件是整个页面)显示在目前页面上,此过程并没有刷新页面。

    • _blank(默认值)是重新打开一个新的页面,每单独打开一个新页面都是涉及到刷新操作的。

    因此可以得出,刷新页面会导致store中存储的state(状态值)全部变回初始值。

    为了佐证这个想法,我刷新了订单管理界面,发现头部的文字变回“首页”(首页是store中该状态的初始值)

    问题3.PNG

    要解决这个问题,需要学习浏览器的缓存机制。而且Redux中提供了redux-persist来实现状态的持久化

    redux-persist

    H5本地存储

    cookies、sessionStorage和localStorage解释及区别

    参考资料,弄懂cookie和webstorage。简单来说就是:

    • cookie在浏览器请求中每次都会附加请求头中发送给服务器。用户代理(一般值浏览器)所实现的大小最少要到达4096字节

    • session:Session用于保存每个用户的专用信息,变量的值保存在服务器端,通过SessionID来区分不同的客户。

    • localStorage保存数据会一直保存没有过期时间,不会随浏览器发送给服务器。大小5M或更大

    • sessionStorage仅当前页面有效一旦关闭就会被释放。也不会随浏览器发送给服务器。大小5M或更大。

    redux-persist初体验

    redux-persist官方文档

    我的需求是刷新页面不会导致store里存储的状态值全部丢失被初始化,这些状态在这此网站请求(一次session)过程中是持久化存储的。当明确这些需求后,redux-persist真的是一个很简单的东西,他就是一个在浏览器本地持久化存储状态的方案。

    store.js中的代码如下,

    import menuReducer from './../reducer/menuReducer'
    import orderReducer from './../reducer/orderReducer'
    import { createStore,combineReducers } from 'redux'
    import { composeWithDevTools } from 'redux-devtools-extension'
    import {persistStore, persistReducer} from 'redux-persist';
    import hardSet from 'redux-persist/lib/stateReconciler/hardSet';
    import storageSession from 'redux-persist/lib/storage/session'
    
    const reducer = combineReducers({
        menu: menuReducer,
        order: orderReducer
    });
    
    const storageConfig = {
        key: 'root', // 必须有的
        storage: storageSession, // 缓存机制,默认为localStorage
        stateReconciler: hardSet, // 查看 'Merge Process' 部分的具体情况
        // whitelist: ['menu','order'] // reducer 里持久化的数据,除此外均为不持久化数据
    }
    const myPersistReducer = persistReducer(storageConfig, reducer)
    const store = createStore(myPersistReducer,composeWithDevTools())
    export const persistor = persistStore(store)
    export default store
    

    storageConfig
    storage的参数选择有storageSession和localStorage

    • 因为我的需求只是刷新不会导致状态丢失。storageSession将状态值存入内存,在关闭所有相关的网页后,store存储的状态值才会丢失、初始化;
    • 如果要保持状态一直存在,保存在硬盘上,下次登录网页的时候,状态值依然是上次的状态值。可以选择默认的localStorage(store不传参即可)。

    stateReconciler的参数有三个选择,根据我的需求选择hardSet即可

    • hardSet (import hardSet from 'redux-persist/lib/stateReconciler/hardSet')直接用将来状态替代初始状态
      • incoming state: { foo: incomingFoo }
      • initial state: { foo: initialFoo, bar: initialBar }
      • reconciled state: { foo: incomingFoo } // note bar has been dropped
    • autoMergeLevel1 (default) 将来状态和初始状态进行合并,将来状态中的所有成员替换在初始状态中的对应成员,其余初始状态的成员不变
      • incoming state: { foo: incomingFoo }
      • initial state: { foo: initialFoo, bar: initialBar }
      • reconciled state: { foo: incomingFoo, bar: initialBar } // note incomingFoo overwrites initialFoo
    • autoMergeLevel2 (import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2') 和autoMergeLevel1类似,但是是浅合并(目前还未没弄清楚浅合并的意义)
      • incoming state: { foo: incomingFoo }
      • initial state: { foo: initialFoo, bar: initialBar }
      • reconciled state: { foo: mergedFoo, bar: initialBar } // note: initialFoo and incomingFoo are shallow merged

    最后需要在最顶层的组件中重新设置一下Redux,利用PersistGate包裹根组件。

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import * as serviceWorker from './serviceWorker';
    import ERouter from './router'
    import { Provider } from 'react-redux'
    import store from './redux/store/index'
    import {persistor} from './redux/store/index'
    import {PersistGate} from 'redux-persist/lib/integration/react';
    
    ReactDOM.render(
        <Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
                <ERouter />
            </PersistGate>   
        </Provider>,
        document.getElementById('root')
    )
    

    最后运行效果如下图所示,圆满完成既定目标

    结果.PNG

    总结

    匆忙之中,并未完全掌握,后续有用到的话,再进一步的深入学习。

    相关文章

      网友评论

          本文标题:React:Redux进阶

          本文链接:https://www.haomeiwen.com/subject/ysddrctx.html