在開發reac單頁面應用的時候,頁面的展示邏輯跟數據狀態的關系管理變得越來越復雜,redux很好的解決這個問題。廢話不多說,直接先上官網api鏈接。
http://cn.redux.js.org/index.html
官方文檔跟你把概念性的東西講解的很清楚的,怎么串聯起來使用,就得多采坑才行。下面就是我踩的一個坑。 react-redux非組件里面store.dispatch(action)頁面不更新的問題。主要是關於store的:
在前面的章節中,我們學會了使用 action 來描述“發生了什么”,和使用 reducers 來根據 action 更新 state 的用法。
Store 就是把它們聯系到一起的對象。Store 有以下職責:
- 維持應用的 state;
- 提供
getState()方法獲取 state;- 提供
dispatch(action)方法更新 state;- 通過
subscribe(listener)注冊監聽器;- 通過
subscribe(listener)返回的函數注銷監聽器。再次強調一下 Redux 應用只有一個單一的 store。當需要拆分數據處理邏輯時,你應該使用 reducer 組合而不是創建多個 store。
根據已有的 reducer 來創建 store 是非常容易的。在前一個章節中,我們使用
combineReducers()將多個 reducer 合並成為一個。現在我們將其導入,並傳遞createStore()。import { createStore } from 'redux' import todoApp from './reducers' let store = createStore(todoApp)
createStore()的第二個參數是可選的, 用於設置 state 初始狀態。這對開發同構應用時非常有用,服務器端 redux 應用的 state 結構可以與客戶端保持一致, 那么客戶端可以將從網絡接收到的服務端 state 直接用於本地數據初始化。let store = createStore(todoApp, window.STATE_FROM_SERVER)
1.問題如下:隨便在一個js工具類里面獲取store之后,再store.dispatch(actions),改變了狀態后頁面無法自動更新?只能在用頁面組件connect自動注入到props里面的dispatch改變的狀態才能自動更新頁面? 2.代碼如下 Home 頁面組件: class Home extends Component{ constructor(props){ super(props); this.goUser = this.goUser.bind(this) } goUser() { let {dispatch} = this.props; // 通過注入的dispatch對象調用就正常,能觸發頁面自動更新 **dispatch(setDialogState({showDialog: true})); // 通過工具類就不行,狀態改變后無法觸發頁面更新 utils.setDialogState({showDialog: true}); this.props.history.push('/user') } render() { return ( <div> <h3>home</h3> <button onClick={this.goUser}>去用戶中心頁面</button> </div> ) } } export default connect()(Home);
======utils.js文件如下: import storeConfigure from '../store'; import {setDialogState} from '../actions'; const appStore = storeConfigure() export default { setDialogState: function(data){ appStore.dispatch(setDialogState(data)) } } user.js頁面組件 import React,{Component} from 'react'; import Dialog from './Dialog'; import { connect } from 'react-redux' class User extends Component{ constructor(props){ super(props); } componentWillMount() { alert('componentWillMount user') } componentWillReceiveProps(nextProps){ alert('componentWillReceiveProps user') } render() { return ( <div> <h3>user</h3> <Dialog show={this.props.showDialog}/> </div> ) } } const mapStateToProps = function(state) { return { showDialog: state.app.showDialog } } export default connect(mapStateToProps)(User);
======reducers文件夾下的app分塊的js內容如下 import * as types from '../actions/actionType' let initialState = { showDialog: false } export function app(state=initialState,action){ switch(action.type){ case types.SET_DIALOG_STATE: return Object.assign({},initialState,action.data); break; default : return Object.assign({},initialState,action.data); break; } } store.js如下: import {createStore} from 'redux'; import reducers from '../reducers'; export default function configureStore(initialState) { let store = createStore(reducers, initialState, // 觸發 redux-devtools window.devToolsExtension ? window.devToolsExtension() : undefined ); return store; }
====全局App.js入口文件
上面問題哪里不對了?。
問題就出在這里:
configureStore()在你的react項目里,只能出現一次,記住只能出現一次!!!
如果出現了多次,就是違背了單一store原則。哪怕你狀態也改了,頁面就是不會自動更新,因為頁面注入的狀態來自於另一個store。
下面就是你的store的寫法,推薦的寫法跟不推薦的寫法。
import {createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk'
import { createLogger } from 'redux-logger'
import reducers from '../reducers';
const loggerMiddleware = createLogger()
// 不推薦的寫法
export default function configureStore(initialState) {
let store = createStore(reducers, initialState,
applyMiddleware(thunkMiddleware, loggerMiddleware),
// 觸發 redux-devtools
window.devToolsExtension ? window.devToolsExtension() : undefined
);
console.log(store)
return store;
}
// 推薦的寫法
function configureStore(initialState) {
let store = createStore(reducers, initialState,
applyMiddleware(thunkMiddleware, loggerMiddleware),
// 觸發 redux-devtools
window.devToolsExtension ? window.devToolsExtension() : undefined
);
console.log(store)
return store;
}
const appStore = configureStore();
export default appStore;
當然,這問題主要使用的場景就是在非react組件里面通過store.dispatch(action)來改變狀態。
比如建立websocket的事件監聽,或者一個普通uitls.js里面的。
有點類似於JavaScript原生的addEventListener。
