用React+Redux+ES6寫一個最傻瓜的Hello World

最近Redux+React彷佛在前端圈子裏愈來愈火了,然而即便是官方的文檔也只給出了一個TodoMVC的範例,裏面上百行的代碼以及過多的新概念,對於不少初學者(包括我)來講依然很複雜。javascript

google百度搜了搜,也一直沒有找到簡單傻瓜如同Hello World的快速入門,因此今天花了一點時間寫了個最最簡單的DEMO(真的是最最簡單了/w\):html

點這裏看DEMO前端

Github:https://github.com/starkwang/react-redux-es6-quickstartjava

1、開發環境搭建

一、webpack

首先咱們須要webpack這個打包工具(若是你已經有了就無視吧):node

sudo npm install -g webpack

二、依賴包

建立一個文件夾,隨便叫什麼名字,好比redux-testreact

mkdir redux-test && cd redux-test

而後用npm安裝如下依賴包:webpack

  1. babel-loadergit

  2. reactes6

  3. react-domgithub

  4. react-redux

  5. redux

三、Webpack的配置文件

這個項目中須要把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

首先的首先,咱們須要一張HTML頁面,這個頁面裏有一個id爲rootdiv做爲咱們應用的根節點:

<!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>

2、開始寫代碼吧

網上React的入門教學實在太多,再也不贅述。

關於Redux,請務必讀完中文文檔的入門部分。

咱們如今主要是要實現DEMO中的效果:
點這裏看DEMO
一、點擊文字的時候,文字會在「Hello」和「Stark」中來回切換;
二、點擊按鈕的時候,文字會變爲「You just click button」。


如下代碼都是在同一個文件index.jsx中!

如下代碼都是在同一個文件index.jsx中!

如下代碼都是在同一個文件index.jsx中!

0、引入依賴包

咱們須要react的本體、react-dom的render方法、redux的createStorebindActionCreators方法,以及react-redux的Providerconnect方法

import React from 'react';
import { render } from 'react-dom';
import { createStore,bindActionCreators } from 'redux';
import { Provider ,connect } from 'react-redux';

一、Action

顯然咱們要定義兩種事件:「文字來回切換」、「按鈕點擊」。

//action
//咱們這裏並無使用const來聲明常量,實際生產中不推薦像下面這樣作
function changeText(){
    return {
        type:'CHANGE_TEXT'
    }
}

function buttonClick(){
    return {
        type:'BUTTON_CLICK'
    }
}

二、Reducer

對於不一樣的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

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>
        );
    }
}

五、鏈接React組件和Redux

//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)

六、渲染咱們的App

//Provider是react-redux直接提供的
//store是咱們在第3步中生成的

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

七、編譯、打包

還記得安裝的webpack和寫好的配置文件嗎?

直接在項目目錄下執行:

webpack

而後就能夠把index.jsx編譯打包成bundle.js

3、index.jsx源代碼

下面是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')
)

4、總結

若是你還能堅持活着看到這裏,你必定在吐槽,「臥槽這種簡單到連jQuery都懶得用的小玩具居然也要寫100+行代碼?」

沒錯,Redux做爲Flux架構的一個變種,原本就是「適合大型應用」的,它解決的是當應用複雜度上升時,數據流混亂的問題,而並不是直接提高你的代碼效率。

有時候用Angular、jQuery甚至原生js就幾行代碼的事,在Redux下卻會分爲action、reducer、store三步來進行。雖然效率低下,可是當項目愈來愈大時,能夠很好地管理項目的複雜度。

相關文章
相關標籤/搜索