React-Redux初實踐

這禮拜終於把手頭的需求完結的差不多了,終於有時間沉澱下這段時間學習到的新技術了。

redux,我是在阮一峯大神的教程裏學習的,先粘上傳送門,大神在3篇連續的教程中,很詳細的講解了redux和React-Redux 的原理和用法,而我接下來主要是整理下我的學習筆記,和我在實踐中走過的坑。

一.我對redux理解

衆所周知,用react去做頁面邏輯的時候,頁面所見的所有dom元素,都可以被拆分成小的組件,如果遇到複雜頁面,層級結構較多的話,組件state狀態的統一管理就會很費勁,redux就是把頁面所有需要共享的狀態統一管理,存儲到一個對象當中,如果在一個組件內部改變了這個state,那麼所有組件用到這個state的地方都會隨之做出改變,做到牽一髮而動全身,不過要提醒大家一點注意的是,如果正如阮一峯大神的寫在前言,對於簡單的路由頁面,是沒有必要一定用redux來管理state的。

二.我的redux實踐

在這裏我舉個簡單栗子,就像我在做的控制檯,整個項目用的react-router前端路由,所有子頁面都是組件,左邊是整體導航,右邊是路由子頁面,當用戶切換右邊tab頁面的時候,父級組件的menu需要做高亮聯動,之前這裏實現,我是用prop-types庫,祖先傳參的方法實現的(具體實現參見上篇),這裏用了redux管理狀態的話,就會很簡單的實現這個需求。


1.安裝

cnpm install redux --save-dev
cnpm install react-redux --save-dev
cnpm install prop-types --save-dev

2.首先,需要在入口index.js即入口文件,創建全局的store存儲狀態對象,Provider在根組件外面包了一層,這樣一來,App的所有子組件就默認都可以拿到state了。

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
//React-Redux 提供Provider組件,可以讓容器組件拿到state。
//它的原理是React組件的context屬性
import { Provider } from 'react-redux';
// import './index.css';
import App from './template/App';
import registerServiceWorker from './registerServiceWorker';
//Store 需要知道 Reducer 函數,做法就是在生成 Store 的時候,將 Reducer 傳入createStore方法
import reducers from './reducers/index';

// console.log(createStore)
//Store 就是保存數據的地方,你可以把它看成一個容器。整個應用只能有一個 Store。
const store = createStore(reducers);
const rootEl = document.getElementById('root');

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

render();
registerServiceWorker();
//設置監聽函數,一旦 State 發生變化,就自動執行這個函數。
store.subscribe(render);

3.創建reducer處理器

我所理解的reducer就是一個switch處理器,根據不同的輸入態,返回對應的輸出態。

src/reducers/index.js

import { combineReducers } from 'redux'
import menuSwitch from './menuSwitch'
import counter from './counter'

const reducers = combineReducers({
	menuSwitch: menuSwitch,
	counter1: counter,
});

export default reducers

src/reducers/menuSwitch.js

const defaultState = 'containerTaskList';
const menuSwitch = (state = defaultState, action) => {
  switch (action.type) {
  case 'MENU_1':
    return 'containerTaskList'
  case 'MENU_2':
    return 'containerContainerList'
  default:
    return state
  }
}

export default menuSwitch

4.子頁面邏輯

src/template/workshop/laboratory/Lab5.js

在子頁面中,如此改變menu菜單的state

store.dispatch({ type: 'MENU_2' });

5.父頁面邏輯

src/template/framework.js

在父級framework裏的render函數裏,用store.getState就可以獲得改變的菜單state

render() {
	let currentMenu1 = this.context.store.getState().menuSwitch;
	return (
		<Menu 
		    selectedKeys={[currentMenu]}
		</Menu>
	)
}

三.踩坑

在react-router路由中,需要把路由配置部分單獨提出來,不然會有如下報錯,雖然是個warning,但是很煩人有木有啊!!

這裏當真是折騰了我整整一晚上,纔在Stack Overflow上找到了解決方案,新改後的路由配置部分如下,把routes單獨提取到變量當中,並且把initFrameWork方法也單獨提取出來了,不知道react-router4裏有沒有改進這個問題。

app.js

const initFrameWork = (nextState, replace, cb) =>{
	//blabla
};


const routes = (
    <Route path="/">
        {/*重定向 到myHome*/}
        <IndexRedirect to="/index" />
        {/*登錄*/}
        <Route path="/login" getComponent={$util.lazyLoadComponent(require('./Login'))}></Route>


        {/*主框架*/}
        <Route path="/frameWork" getComponent={$util.lazyLoadComponent(require('./FrameWork'))} onEnter={initFrameWork}>
    </Route>
)


class App extends Component {
    state = {
    };
    render() {
        return (
            <Router history={browserHistory}>
                { routes }
            </Router>
        );
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章