在這篇文章,咱們將深刻探討 Redux 並瞭解爲何用它構建一個 React 應用時是頗有價值的。我也將帶您構建您的第一個 Redux 應用,包括如何使用 Stormpath React SDK 做爲 身份認證。以後您能夠把這些知識應用到您現有的 React 應用中!javascript
Redux 是一個幫您在應用中管理 state 的庫。它的設計源自 Flux,可是避開了 Flux 編寫應用的複雜性。若是您已經編寫了一個 Flux 應用,您會很快發現使用 Redux 須要手動編寫以前全部的樣板。此外與 Flux 不一樣的是,您有一個單一的 state 容器。這是一個很大的優點,由於它會使 state 共享和代碼重用讓您構建應用輕鬆不少。html
store 僅是一個 state 容器。這是存儲 state 並在哪裏 actions 被調度及處理的地方。當您開始構建一個 Redux 應用,您要思考如何在應用中存儲模塊和 state。這很重要由於 Redux 建議只有一個 store,而且因爲 state 共享這是以前想到的一個不錯的想法。java
Actions 是表示如何週轉咱們 state 狀態的對象。您能夠把 actions 視爲 state 樹的 API。爲了說明,一個添加新用戶的 action 能夠是:react
{ type: 'ADD_USER', data: { name: 'Foo', email: 'foo@bar.com', password: 'Foobar123_' } }
爲了讓操做變得更清晰和更容易複用,一般使用一個建造者模式來建立 action 對象。例如在上述狀況,您能夠爲這個對象建立一個函數如 addUser(name, email, password)
。正如您所看到的,actions 自己並不操做任何東西。action 僅僅是一個描述咱們如何改變 state 的對象。git
Actions 很酷,但它們對自身並無太大的意義。這就是 reducers 的由來。Reducers 在 store 中經過分發處理 action 來減小這些 actions 對 state 的改變。若是咱們在 store 分發一個 action 如 ADD_USER
,咱們能夠用 reducer 將那些添加新用戶的 action 入口到 state。github
如今您瞭解了基礎知識,讓咱們繼續設計和構建第一個由 Redux 驅動的應用。redux
爲了讓操做變的簡單,咱們構建一個 to-do 應用。這樣咱們就能夠玩轉大部分 Redux 中最重要的概念而不是過於關注於應用自身。app
若是咱們想到一個 to-do 應用,咱們將會須要一些基本的事項。首先一個 to-do 一般由一個列表組成。另外,這個列表包含咱們能夠更改的待辦事項。dom
從一個 state 角度來看,咱們這個應用的模型相似這樣:函數
{ todo: { items: [ { message: "Finish Redux blog post...", completed: false } ] } }
添加待辦事項到 state ?首先,咱們但願添加新的待辦事項到其中。讓咱們建立一個 action :
function addTodo(message) { return { type: 'ADD_TODO', message: message, completed: false }; }
注意這裏的 type
字段。這個應該是個惟一的名稱用於描述您的 action。一般這個類型是大寫格式並用底劃線做爲單詞分隔符。另外您將使用這個名稱/標識符在 reducers 中處理具體的 actions 並改變它們的 state 。
一旦咱們增長了新的待辦事項,咱們確定但願可以將其標記爲已完成,咱們也但願可以將其刪除,甚至能夠清除全部待辦事項。
所以讓咱們也爲這些操做添加 actions :
function completeTodo(index) { return { type: 'COMPLETE_TODO', index: index }; } function deleteTodo(index) { return { type: 'DELETE_TODO', index: index }; } function clearTodo() { return { type: 'CLEAR_TODO' }; }
如今咱們已經有了 actions,讓咱們繼續構建 store。若是您還記的剛剛說的,store 是 Redux 應用的核心,關聯全部的 state,調度 actions 和 reducers 處理。
import { createStore } from 'redux'; var defaultState = { todo: { items: [] } }; function todoApp(state, action) { } var store = redux.createStore(todoApp, defaultState);
如今當咱們有一些 actions 和 store,讓咱們建立第一個 reducer。若是您還記的剛剛說的,reducer 只是一個處理器您能夠用它來處理 actions 和改變 state。
所以咱們開始處理 ADD_TODO
action 以下所示:
function todoApp(state, action) { switch (action.type) { case 'ADD_TODO': return Object.assign({}, state, { items: items.concat([{ message: action.message, completed: false }]) }); default: return state; } }
注意當咱們說一個 reducer 「改變」 state 時,若是一個 state 須要改變,實際它所作的是建立一個 state 副本並做出改變。若是沒有變化,那麼返回相同的 state。但在任何狀況下您都不該該直接改變 state 由於這樣意味着改變 state history 。
如今當咱們有了第一個 action 處理器,讓咱們爲它們增長其他的支持:
function todoApp(state, action) { switch (action.type) { case 'ADD_TODO': return Object.assign({}, state, { todo: { items: items.concat([{ message: action.message, completed: false }]) } }); case 'COMPLETE_TODO': var items = [].concat(state.todo.items); items[action.index].completed = true; return Object.assign({}, state, { todo: { items: items } }); case 'DELETE_TODO': var items = [].concat(state.todo.items); items.splice(action.index, 1); return Object.assign({}, state, { todo: { items: items } }); case 'CLEAR_TODO': return Object.assign({}, state, { todo: { items: [] } }); default: return state; } }
如今咱們已經有了業務邏輯,讓咱們寫一些 UI 代碼。因爲大部分是常見的 React 知識而且很是相似 Flux 構建的應用, 就再也不深刻講解。
import React from 'react'; import ReactDOM from 'react-dom'; import { createStore } from 'redux'; var defaultState = { todo: { items: [] } }; // 添加咱們在前面步驟中建立的 actions ... function todoApp(state, action) { // 添加咱們在前面步驟中的 reducer 邏輯... } var store = redux.createStore(todoApp, defaultState); class AddTodoForm extends React.Component { state = { message: '' }; onFormSubmit(e) { e.preventDefault(); store.dispatch(addTodo(this.state.message)); this.setState({ message: '' }); } onMessageChanged(e) { var message = e.value.trim(); this.setState({ message: message }); } render() { return ( <form onSubmit={this.onFormSubmit.bind(this)}> <input type="text" placeholder="Todo..." onChange={this.onMessageChanged.bind(this)} value={this.state.message} /> <button type="submit" value="Add" /> </form> ); } } class TodoItem extends React.Component { onDeleteClick() { store.dispatch(deleteTodo(this.props.index)); } onCompletedClick() { store.dispatch(completeTodo(this.props.index)); } render() { return ( <li> <a href="#" onClick={this.onDeleteClick.bind(this)}>[x]</a> <a href="#" onClick={this.onCompletedClick.bind(this)}>{this.props.message}</a> </li> ); } } class TodoList extends React.Component { state = { items: [] }; componentWillMount() { store.subscribe(() => { var state = store.state(); this.setState({ items: state.todo.items }); }); } render() { var items = []; this.state.items.forEach((item, index) => { items.push(<TodoItem index={index} message={item.message} completed={item.completed} />); }); return ( <ol>{ items }</ol> ); } } ReactDOM.render( <div> <h1>Todo</h1> <AddTodoForm /><hr /> <TodoList /> </div>, document.getElementById('app') );
正如您所看到的,構建 Redux 應用 UI 部分並不難。惟一的區別就是您用 store.subscribe(listener)
來監聽 state 改變,而後經過 store.getState()
檢索 state。但除此以外,它很是像一個 Flux 構建的應用。
由於有至關多須要增長 Redux 支持 Stormpath React SDK 需求,咱們說幹就幹。若是您但願爲 Redux 配置這個 SDK,簡單的配置這個 Stormpath React SDK dispatcher
選項並設置 type
爲 redux
指向 store
到您的 Redux store 以下所示:
function myApp(state, action) { return state; } ReactStormpath.init({ dispatcher: { type: 'redux', store: createStore(myApp) } });
一旦完成這些您能夠攔截並處理一切 Stormpath React SDK 的 actions 調度。例如,您但願用用戶數據來豐富 state,而後簡單處理這個 USER_SET
action 並將用戶數據添加到 state。
function myApp(state, action) { switch (action.type) { case 'USER_SET': return Object.assign({}, state, { user: action.data }); default: return state; } }
正如您在這篇文章所看到的,構建一個由 Redux 驅動的應用是很是容易和簡單的。這很像構建一個 Flux, 只是是概念略有不一樣並有較少的樣板代碼編寫。
但願您喜歡這個教程,可以在未來利用它。
若是遇到任何沒法運行或者問題,不妨看下 參考應用。
想了解更多關於 React 應用增長身份認證的內容?看看這些教程:
原文地址:https://stormpath.com/blog/build-a-redux-powered-react-application/