在使用React和React-router實現單頁面應用時,會有這樣一個場景:從列表頁面點擊某項條目進入詳情頁,而後回退至列表頁面時,列表頁面會從新刷新,不只數據從新獲取了,滾動條也回到了頂部。用戶要繼續查看剩餘數據的話,須要從新滑動到以前點擊的那個條目,若是列表作了分頁的話就更麻煩了,這對於用戶體驗來講是很是很差的。react
因此咱們但願能作到,從二級頁面回退至列表頁面時,列表頁面能保留以前的狀態(數據和滾動條位置)。npm
那麼怎麼實現呢?下面分享一下React經過redux來緩存列表數據以及滑動位置,以達到保留列表頁面狀態的方法。redux
關於redux以及react-redux的使用,這裏就不作講解了,能夠參考我以前寫的 React-redux的原理以及使用 。固然網絡上有不少講解得更清晰的文章,讀者能夠自行搜索。緩存
下面直接進入正題,介紹實現需求的步驟吧bash
cnpm install redux react-redux -dev --save網絡
/**
* 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也是頗有必要的。佈局
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()()*方法更新緩存中相應的數據,將該條數據的狀態改成已簽到。這樣回退至列表頁面時,該條數據的展現纔會正確。ui
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持久化數據存儲 有作簡單講解。this
<父佈局
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來獲取父佈局的滑動距離spa
首先經過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緩存列表數據以及滑動位置,回退時恢復頁面狀態的需求。