最近Redux+React彷佛在前端圈子裏愈來愈火了,然而即便是官方的文檔也只給出了一個TodoMVC的範例,裏面上百行的代碼以及過多的新概念,對於不少初學者(包括我)來講依然很複雜。javascript
google百度搜了搜,也一直沒有找到簡單傻瓜如同Hello World的快速入門,因此今天花了一點時間寫了個最最簡單的DEMO(真的是最最簡單了/w\):html
點這裏看DEMO前端
Github:https://github.com/starkwang/react-redux-es6-quickstartjava
首先咱們須要webpack這個打包工具(若是你已經有了就無視吧):node
sudo npm install -g webpack
建立一個文件夾,隨便叫什麼名字,好比redux-test
。react
mkdir redux-test && cd redux-test
而後用npm安裝如下依賴包:webpack
babel-loadergit
reactes6
react-domgithub
react-redux
redux
這個項目中須要把ES六、JSX轉換爲瀏覽器可運行的ES5語法,因此咱們須要使用webpack及其babel-loader來進行轉換、打包。這裏咱們默認index.jsx
是入口文件。
//webpack.config.js module.exports = { entry: 'index.jsx', output: { filename: 'bundle.js' }, module: { loaders: [{ test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, loader: 'babel', // 'babel-loader' is also a legal name to reference query: { presets: ['es2015','react'] } }] } };
把這個webpack.config.js
放到目錄下便可。
首先的首先,咱們須要一張HTML頁面,這個頁面裏有一個id爲root
的div
做爲咱們應用的根節點:
<!DOCTYPE html> <html> <head> <title>React-Redux Hello World</title> </head> <body> <div id="root"></div> </body> <script type="text/javascript" src="bundle.js"></script> </html>
網上React的入門教學實在太多,再也不贅述。
關於Redux,請務必讀完中文文檔的入門部分。
咱們如今主要是要實現DEMO中的效果:
點這裏看DEMO
一、點擊文字的時候,文字會在「Hello」和「Stark」中來回切換;
二、點擊按鈕的時候,文字會變爲「You just click button」。
如下代碼都是在同一個文件index.jsx中!
如下代碼都是在同一個文件index.jsx中!
如下代碼都是在同一個文件index.jsx中!
咱們須要react的本體、react-dom的render
方法、redux的createStore
和bindActionCreators
方法,以及react-redux的Provider
和connect
方法
import React from 'react'; import { render } from 'react-dom'; import { createStore,bindActionCreators } from 'redux'; import { Provider ,connect } from 'react-redux';
顯然咱們要定義兩種事件:「文字來回切換」、「按鈕點擊」。
//action //咱們這裏並無使用const來聲明常量,實際生產中不推薦像下面這樣作 function changeText(){ return { type:'CHANGE_TEXT' } } function buttonClick(){ return { type:'BUTTON_CLICK' } }
對於不一樣的action,對應的狀態轉換也不同:
//reducer //最初的狀態是"Hello" const initialState = { text: 'Hello' } function myApp(state = initialState, action) { switch (action.type) { case 'CHANGE_TEXT': return { text:state.text=='Hello'?'Stark':'Hello' } case 'BUTTON_CLICK': return { text: 'You just click button' } default: return { text:'Hello' } } }
Store是由Redux直接生成的:
let store = createStore(myApp);
這裏一共有三個組件:文字組件Hello
、按鈕Change
、以及它們的父組件App
//Hello class Hello extends React.Component{ constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick(){ this.props.actions.changeText(); } render() { return ( <h1 onClick={this.handleClick}> {this.props.text} </h1> ); } }
//Change class Change extends React.Component{ constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick(){ this.props.actions.buttonClick(); } render() { return ( <button onClick={this.handleClick} >change</button> ); } }
//App class App extends React.Component{ constructor(props) { super(props); } render() { //actions和text這兩個props在第5步中會解釋 const { actions, text} = this.props; return ( <div> <Hello actions={actions} text={text}/> <Change actions={actions}/> </div> ); } }
//mapStateToProps的做用是聲明,當state樹變化的時候,哪些屬性是咱們關心的? //因爲咱們這個應用過小,只有一個屬性,因此只有text這個字段。 function mapStateToProps(state) { return { text: state.text } } //mapDispatchToProps的做用是把store中的dispatch方法注入給組件 function mapDispatchToProps(dispatch){ return{ actions : bindActionCreators({changeText:changeText,buttonClick:buttonClick},dispatch) } } //這裏實際上給了App兩個props:text和actions,即第4步中的那段註釋 App = connect(mapStateToProps,mapDispatchToProps)(App)
//Provider是react-redux直接提供的 //store是咱們在第3步中生成的 render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
還記得安裝的webpack和寫好的配置文件嗎?
直接在項目目錄下執行:
webpack
而後就能夠把index.jsx
編譯打包成bundle.js
了
下面是index.jsx的完整源碼,能夠直接複製
import React from 'react'; import {render} from 'react-dom'; import { createStore,bindActionCreators } from 'redux'; import { Provider ,connect} from 'react-redux'; //action function changeText(){ return { type:'CHANGE_TEXT' } } function buttonClick(){ return { type:'BUTTON_CLICK' } } //reducer const initialState = { text: 'Hello' } function myApp(state = initialState, action) { switch (action.type) { case 'CHANGE_TEXT': return { text:state.text=='Hello'?'Stark':'Hello' } case 'BUTTON_CLICK': return { text: 'You just click button' } default: return { text:'Hello' }; } } //store let store = createStore(myApp); class Hello extends React.Component{ constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick(){ this.props.actions.changeText(); } render() { return ( <h1 onClick={this.handleClick}> {this.props.text} </h1> ); } } class Change extends React.Component{ constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick(){ this.props.actions.buttonClick(); } render() { return ( <button onClick={this.handleClick} >change</button> ); } } class App extends React.Component{ constructor(props) { super(props); } render() { const { actions, text} = this.props; return ( <div> <Hello actions={actions} text={text}/> <Change actions={actions}/> </div> ); } } function mapStateToProps(state) { return { text: state.text } } function mapDispatchToProps(dispatch){ return{ actions : bindActionCreators({changeText:changeText,buttonClick:buttonClick},dispatch) } } App = connect(mapStateToProps,mapDispatchToProps)(App) render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
若是你還能堅持活着看到這裏,你必定在吐槽,「臥槽這種簡單到連jQuery都懶得用的小玩具居然也要寫100+行代碼?」
沒錯,Redux做爲Flux架構的一個變種,原本就是「適合大型應用」的,它解決的是當應用複雜度上升時,數據流混亂的問題,而並不是直接提高你的代碼效率。
有時候用Angular、jQuery甚至原生js就幾行代碼的事,在Redux下卻會分爲action、reducer、store三步來進行。雖然效率低下,可是當項目愈來愈大時,能夠很好地管理項目的複雜度。