美文网首页redux
React通过redux缓存列表数据以及滑动位置,回退时恢复页面

React通过redux缓存列表数据以及滑动位置,回退时恢复页面

作者: RaoMeng | 来源:发表于2019-02-22 11:35 被阅读0次

    在使用ReactReact-router实现单页面应用时,会有这样一个场景:从列表页面点击某项条目进入详情页,然后回退至列表页面时,列表页面会重新刷新,不仅数据重新获取了,滚动条也回到了顶部。用户要继续查看剩余数据的话,需要重新滑动到之前点击的那个条目,如果列表做了分页的话就更麻烦了,这对于用户体验来说是非常不好的。

    所以我们希望能做到,从二级页面回退至列表页面时,列表页面能保留之前的状态(数据和滚动条位置)。

    那么怎么实现呢?下面分享一下React通过redux来缓存列表数据以及滑动位置,以达到保留列表页面状态的方法。

    关于redux以及react-redux的使用,这里就不做讲解了,可以参考我之前写的 React-redux的原理以及使用 。当然网络上有很多讲解得更清晰的文章,读者可以自行搜索。

    下面直接进入正题,介绍实现需求的步骤吧

    1、安装redux以及react-redux

    cnpm install redux react-redux -dev --save

    2、编写操作列表页面相关数据的action

    /**
     * Created by RaoMeng on 2018/12/10
     * Desc: 列表数据缓存
     */
    
    import {CLEAR_LIST_STATE, LIST_STATE} from "../constants/actionTypes";
    import store from '../store/store'
    
    /**
     * 保存列表状态
     * @param data
     * @returns {Function}
     */
    export const saveListState = (data) => {
        return () => {
            store.dispatch({
                type: LIST_STATE,
                ...data
            })
        }
    }
    
    /**
     * 清除列表状态
     * @returns {Function}
     */
    export const clearListState = () => {
        return () => {
            store.dispatch({
                type: CLEAR_LIST_STATE
            })
        }
    }
    

    这里实现了两个actionType,一个是保存列表状态,一个是清除列表状态。
    保存列表状态就是为了达到回退时不刷新页面的需求;
    清除列表状态则是因为:从菜单页面进入列表页面时,是要求重新加载页面数据的,假如不清除redux中的缓存数据,页面就会读取缓存数据而不会重新请求网络数据,所以这个action也是很有必要的。

    3、实现配合action操作state的reducer

    import {CLEAR_LIST_STATE, LIST_STATE} from "../constants/actionTypes";
    
    const initListState = {
        scrollTop: 0,//列表滑动位置
        listData: [],//列表数据
        pageIndex: 1,//当前分页页码
        itemIndex: -1,//点击的条目index
    }
    
    const redListState = (state = initListState, action) => {
        if (action === undefined) {
            return state
        }
    
        switch (action.type) {
            case LIST_STATE:
                //更新列表状态
                return {
                    ...state,
                    ...action
                }
            case CLEAR_LIST_STATE:
                //清空列表状态
                return initListState
            default:
                return state
        }
    
    }
    
    export default redListState
    
    /**
     * Created by RaoMeng on 2018/12/10
     * Desc: 数据处理中心
     */
    
    import {combineReducers} from 'redux'
    import redUserInfo from './redUserInfo'
    import redListState from './redListState'
    import redClassData from './redClassData'
    
    const reducers = combineReducers({redUserInfo, redListState, redClassData})
    
    export default reducers
    

    这里解释下为什么要记录分页页码以及点击的条目index
    记录分页页码只是在列表数据做了分页的情况下需要。是为了回退到列表页面后,用户继续上拉加载数据时页码是正确的。
    记录点击的条目index则是为了能在详情页更新所点击的条目数据。比如说一个会议签到列表,用户点击某条数据进入详情页后,点击签到按钮,这时我们要根据itemIndex来调用action的saveListState()()方法更新缓存中相应的数据,将该条数据的状态改为已签到。这样回退至列表页面时,该条数据的展示才会正确。

    4、创建store

    import {createStore} from 'redux'
    import reducers from '../reducers/index'
    import {persistStore, persistReducer} from 'redux-persist';
    import storage from 'redux-persist/lib/storage';
    import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
    
    const persistConfig = {
        key: 'root',
        storage: storage,
        stateReconciler: autoMergeLevel2 // 查看 'Merge Process' 部分的具体情况
    };
    
    const myPersistReducer = persistReducer(persistConfig, reducers)
    
    const store = createStore(myPersistReducer)
    
    export const persistor = persistStore(store)
    export default store
    
    

    这里用到了redux-persist来实现redux数据的持久化存储,我在 React通过redux-persist持久化数据存储 有做简单讲解。

    5、在点击条目的回调事件中调用saveListState方法保存列表状态

        <父布局
            ref={el => {
                   this.container = el
            }}
            > </父布局>
    
        onItemClick = index => {
            console.log('scrollTop', ReactDOM.findDOMNode(this.container).scrollTop)
            saveListState({
                scrollTop: ReactDOM.findDOMNode(this.container).scrollTop,
                listData: this.state.meetingSignList,
                pageIndex: mPageIndex,
                itemIndex: index,
            })()
    
            const {meetingSignList} = this.state
            this.props.history.push('/meet-detail/' + meetingSignList[index].meetId)
        }
    

    通过ReactDOM.findDOMNode(this.container).scrollTop来获取父布局的滑动距离

    6、在页面的componentDidMount方法中获取redux数据

    首先通过react-redux的connect方法将state中的数据绑定到页面的props中,方便访问

    
    let mapStateToProps = (state) => ({
        listState: {...state.redListState}
    })
    
    let mapDispatchToProps = (dispatch) => ({})
    
    export default connect(mapStateToProps, mapDispatchToProps)(MeetingSignIn)
    

    这样,在页面中就可以通过this.props.listState来访问redux中缓存的列表数据了

    然后,在componentDidMount中获取缓存的列表数据,如果有缓存数据,则加载,如果没有则重新请求

    componentDidMount() {
            document.title = '会议管理'
            console.log('listState', this.props.listState)
            if (this.props.listState && !isObjEmpty(this.props.listState.listData)) {
                this.setState({
                    meetingSignList: this.props.listState.listData,
                    isLoading: false,
                }, () => {
                    ReactDOM.findDOMNode(this.container).scrollTop = this.props.listState.scrollTop
                })
                mPageIndex = this.props.listState.pageIndex
            } else {
                Toast.loading('数据加载中...', 0)
                mPageIndex = 0
                this.loadMeetList()
            }
        }
    

    这样就实现了React通过redux缓存列表数据以及滑动位置,回退时恢复页面状态的需求。

    相关文章

      网友评论

        本文标题:React通过redux缓存列表数据以及滑动位置,回退时恢复页面

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