redux的文档写得很好,详细的介绍了redux的设计思想、核心概念、A PI以及如何搭配react使用。但是官网的TodoList对于初学者还是有点 难度的,所以我这里写 了一个超级简单的例子,手把手教你从react到redux再到react-redux,来帮助你认识、使用和巩固redux以及react -redux。

前提条件

本片教程需要您掌握以下基础知识:

  1. react的基础知识,如:组件,state,props、refs和组件间的通信方式
  2. redux的基本概念,如:核心概念、三大原则、action、reducer、store
  3. react-redux的两个“魔法”, Provider组件和connect()方法

如果你还未掌握以上知识,您可以

  1. 移步到我的这篇react入门教程学习
  2. 去redux中文官网学习
  3. 移步到我的这篇箭头函数教程学习

预览

img

最后的效果就是这样,是不是很简单。

为了让您的印象更深刻,本篇的教程使用三种方式完成。先用react完成,然后在搭配redux,最后在使用react+redux+react-redux完成。

下面正式开始

开发工具

WebStorm

创建项目

使用WebStorm自带的脚手架create-react-app一键创建,免去搭建项目的繁琐步骤和时间

项目结构

在src目录下新建两个文件夹:componetns和redux

如图所示:

img

方式一:纯react

在src/componetns目录下新建js文件Count

src/components/Count的代码如下:

import React, { Component } from 'react';

class Count extends Component{

    //初始化状态
    constructor(props){
        super(props)
        this.state = {
            count: 0
        }
    }

    //增加的方法
    increment(){
        //获取当前鼠标选择的数字
        const number = this.refs.numSelect.value * 1;
        //更新state
        this.setState({
            count: this.state.count + number
        });
    }

    //减少的方法
    decrement(){
        //获取当前鼠标选择的数字
        const number = this.refs.numSelect.value * 1;
        //更新state
        this.setState({
            count: this.state.count - number
        });
    }
    render() {
        //获取state的值
        const count = this.state.count
        return (
            <div>
                <p>计数结果{count}</p>
                <select ref="numSelect">
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button onClick={() => this.increment()}>+</button>
                <button onClick={() => this.decrement()}>-</button>
            </div>
        );
    }
}

export default Count;

src/App的代码如下:

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

import Count from './componetns/Count';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Count/>
      </div>
    );
  }
}

export default App;

src/index的代码如下:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(
    <App />,
    document.getElementById('root')
);

运行npm start,结果和预览的效果是一模一样的,纯react实现就是这么简单!

方式二:react+redux

1. 定义action-types

在src/redux目录下新建文件action-types,用来存放将要用到的常量。

代码如下:

//增加
export const INCREMENT = 'INCREMENT';
//减少
export const DECREMENT = 'DECREMENT';

2. 定义actions

在src/redux目录下新建文件actions

代码如下:

//引入我们之前定义好的常量
import {INCREMENT,DECREMENT} from './action-types';

//增加的动作
export const increment = (number) => ({type: INCREMENT,data: number});

//减少的动作
export const decrement = (number) => ({type: DECREMENT,data: number});

3. 定义reducer

在src/redux目录下新建文件reducers,存放我们reducer的具体逻辑

代码如下:

//首先引入我们之前定义好的常量
import {INCREMENT,DECREMENT} from './action-types';

/**
 * reducer的语法基本都是套路
 * 作用:接受一个state和action,返回一个新的state,注意不能改变老的state。
 * @param state:状态,这里给形参赋初始值
 * @param action:动作对象,格式是固定的,如:{type: 'aaa',data: bbb}
 */
export function count(state = 0,action) {
    switch (action.type) {
        case INCREMENT :
            return state + action.data
        case DECREMENT :
            return state - action.data
        default :
            return state
    }
}

这段代码应该很容易理解吧

4. 定义store

  1. 首先下载redux
npm install --save redux
  1. 在src/redux目录下新建文件store

代码如下:

import React from 'react';
//引入redux
import {createStore} from 'redux';
//引入我们定义好的reducer
import {count} from './reducers';

//用redux提供的createStore方法创建store
export default createStore(count);

5. 将store作为属性传递给Count组件

修改src/App的代码

import React, { Component } from 'react';
import './App.css';

import Count from './componetns/Count';

//引入我们定义好的store,并作为属性传递给Count组件
import store from './redux/store';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Count store={store}/>
      </div>
    );
  }
}

export default App;

6. 然后在Count组件里调用store

修改src/components/Count的代码

import React, { Component } from 'react';

//引入我们定义好的action
import {increment,decrement} from '../redux/actions';

class Count extends Component{

    //增加的方法
    increment(){

        //获取当前鼠标选择的数字
        const number = this.refs.numSelect.value * 1;
        
        //(方式二)获取store
        const store = this.props.store;

        /**
         * (方式二)
         * 使用store里的dispatch方法获取新的state,
         * dispatch方法接受的参数是action,它会根据你定义的reducer的逻辑返回新的state
         */
        store.dispatch(increment(number));

    }

    //减少的方法
    decrement(){

        //获取当前鼠标选择的数字
        const number = this.refs.numSelect.value * 1;

        //获取store(方式二)
        const store = this.props.store;

        /**
         * (方式二)
         * 使用store里的dispatch方法获取新的state,
         * dispatch方法接受的参数是action,它会根据你定义的reducer的逻辑返回新的state
         */
        store.dispatch(decrement(number));
    }
    render() {

        //(方式二)使用store的getState()方法获取state,因为state交给了redux管理,所以用这种方式获取state
        const count = this.props.store.getState()
        return (
            <div>
                <p>计数结果{count}</p>
                <select ref="numSelect">
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button onClick={() => this.increment()}>+</button>
                <button onClick={() => this.decrement()}>-</button>
            </div>
        );
    }
}

export default Count;

7.修改src/index的代码

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

//引入我们之前定义好的store
import store from './redux/store';

//将render提取出来
const render = () => {
    ReactDOM.render(
        <App />,
        document.getElementById('root')
    );
}

//首先初始化界面
render();

//当state更新时,使用store提供的subscribe()方法监听state并重新渲染组件
store.subscribe(render);

至此我们react+redux的方式已经全部完成了,运行出来的结果一模一样。

方式三:react+redux+react-redux

修改src/componetns/Count组件的代码

首先下载react-redux

npm install --save react-redux

修改代码:

import React, { Component } from 'react';

//引入我们定义好的action
import {increment,decrement} from '../redux/actions';

//引入react-redux的connect()方法
import {connect} from 'react-redux';

class Count extends Component{

    //增加的方法
    increment(){

        //获取当前鼠标选择的数字
        const number = this.refs.numSelect.value * 1;
        
        //(方式三)使用react-redux更新state
        this.props.increment(number);

    }

    //减少的方法
    decrement(){

        //获取当前鼠标选择的数字
        const number = this.refs.numSelect.value * 1;

        //(方式三)使用react-redux更新state
        this.props.decrement(number);
    }

    render() {
       
        //方式三:获取state的值
        const count = this.props.count;

        return (
            <div>
                <p>计数结果{count}</p>
                <select ref="numSelect">
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button onClick={() => this.increment()}>+</button>
                <button onClick={() => this.decrement()}>-</button>
            </div>
        );
    }
}

/**
 * 这里的语法很怪,而且很难理解,我觉得这一步是最难的。我是这样理解:
 * 1. react-redux的connect()方法将当前的组件与redux连接。
 * 2. state => ({count: state}),这是一个带参数(state)的箭头函数,它返回一个对象,
 *    这个对象的key是count(名字可以随便取),value是这个参数(state),所以你可以用this.props.count获取到re
 *    duces返回的state
 * 3. 将increment和decrement这两个action交给store管理,自动调用store.dispatch() 
 *    方法,将action作为参数传进去。
 *    分别作为属性名为increment(属性名可以随便取)和decrement的值,这个值是一个函数。
 *    相当于:const increment = store.dispatch(increment(number));
 *            const decrement = store.dispatch(decrement(number));
 *    然后当前组件可以通过this.props.increment和this.props.decrement获取到这两个函数。
 */
export default connect(
    state => ({
        count: state
    }),
    {increment: increment,decrement: decrement}
)(Count);

修改src/index的代码

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

//引入我们之前定义好的store
import store from './redux/store';

//引入react-redux的Provider组件,这个Provider组件包裹所有的子组件,并将store作为参数传递给所有的子组件
import {Provider} from 'react-redux';

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

//首先初始化界面
render();

//当state更新时,使用store提供的subscribe()方法监听state并重新渲染组件
//使用react-redux的Provider组件,就不再需要监听state了
//store.subscribe(render);

至此,react+redux+react-redux的方式完成了!

原文链接:https://miansen.wang/2018/10/01/1/