Redux教程2:链接React

通过前面的教程,我们有了简单的环境,并且可以运行 Redux 的程序,也对 如何编写Redux示例 有了初步的印象;

掌握了 使用Redux控制状态转移,继而驱动 React 组件发生改变,这才是学习Redux的初衷。

本篇我们将 Redux 和 React 联合起来,着重讲解 redux-react 模块的使用;

1、编写红绿灯React组件

在原有的基础上,我们编写红绿灯组件:

touch components/light/index.js components/light/index.less

在 components/light/index.js 中写React代码,其结构非常简单:

import React, { PropTypes, Component } from 'react'
import { render } from 'react-dom'
import classnames from 'classnames'
import './index.less'

class Light extends Component{
    render(){
        let color = this.props.light.color;
        return(
            <div className="traffic-light">
                <span className={classnames('light',color)} />
            </div>
        )
    }
}

Light.propTypes = {
    light: PropTypes.object.isRequired
}

Light.defaultProps = {
    light : {color:'red',time:'4'}
}

export default Light

根据更改样式类名('red'、'green'、'yellow'),从而移动 sprite图 产生灯变换的效果:

.traffic-light{
  .light{
    display: inline-block;
    background: url(//lh3.googleusercontent.com/-YWLqWZXDYHU/VmWC7GHoAuI/AAAAAAAACgk/nXvEmSWAhQU/s800/light.png) no-repeat 0 0;
    background-size: auto 100%;
    overflow: hidden;
    width:140px / 2;
    height:328px / 2;

    &.red{
      background-position: 0,0;
    }
    &.yellow{
      background-position: -78px , 0;
    }
    &.green{
      background-position: -156px , 0;
    }
  }
}

修改 components/light/demo.js 文件代码为:

import React, {Component, PropTypes} from 'react'
import {render} from 'react-dom'
import Light from './index'

var color = 'red';

render(
    <div id="traffic">
        <Light color={color}/>
    </div>,
    document.getElementById('demo')
)

这样就能通过 http://localhost:3000/light/demo 预览这个组件了;

2、链接React和redux

有了React和之前的Redux,现在就要将两者链接起来了。我们的目标是让红绿灯运行起来,就好比平时在十字路口看到的那样;

2.1、创建示例文件

再创建一个示例文件,就不叫demo了,叫做redux好了:

touch components/light/redux.js

之所以示例文件名称为 demo.js 或 redux.js ,是因为我在 webpack.config.js 中配置了,如果想用其他的文件名,只要依样画葫芦就可以;

首先在 components/light/redux.js 中输入最基本的脚手架代码,引入所需要的组件或模块:

import React, {Component, PropTypes} from 'react'
import {render} from 'react-dom'
import { Provider, connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import * as LightActions from '../../actions/light/'
import lightStore from '../../stores/light/'
import Light from './index'

// 声明store
let store = lightStore();

2.2、创建容器React

继而创建一个 App React类 ,作为总的容器,将上述的 Light 组件放入其中:

import React, {Component, PropTypes} from 'react'
import {render} from 'react-dom'
import { Provider, connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import * as LightActions from '../../actions/light/'
import lightStore from '../../stores/light/'
import Light from './index'

// 声明store
let store = lightStore();

class App extends Component{
    _bind(...methods){
        methods.forEach((method)=>this[method] = this[method].bind(this));
    }
    constructor(){
        super();
        this._bind('autoChange','handleClick');
        this.state = {
            count : 0,
            timeId : null
        }
    }

    autoChange(){ // 自动更改红绿灯
        var _self = this;

        // 这里放置逻辑代码

        this.state.timeId = setTimeout(function(){
            // 递归调用,实现 setInterval 方法
            _self.autoChange();
        },1000);
    }
    handleClick(e){  // 用点击模拟红路灯

        if(this.state.timeId){
            clearTimeout(this.state.timeId);
            this.state.timeId = null;
        } else {
            this.autoChange();
        }

    }
    render(){
        // 通过connect 注入 redux 的 dispatch 方法
        return (
            <div id="traffic" onClick={this.handleClick}>
                <Light light={'yellow'}/>
            </div>
        )
    }
}

上面的代码还是个半成品,看不到效果;简单描述一下上面的代码做了什么:

  • 定义 App 容器,将 Light 组件放在其 render 方法中
  • constructor 方法引用了 _bind方法,方便一次性绑定 this 上下文,该方法来自文章 Refactoring React Components to ES6 Classes
  • handleClick 方法是纯粹是为了演示,当用户点击红绿灯的时候,红绿灯调用 autoChange方法 开始自动变换,用户再次点击的时候就停止变换;
  • autoChange 方法用于红绿灯状态自动转换的,这里占位;本质是使用 setTimeout 代替 setInterval 实现;

2.3、链接React组件和Redux类

这是最为关键的一个步骤,


  ...

class App extends Component{

    ...
}

// 声明 connect 连接
// 将 redux 中的 state传给 App
function mapStateToProps(state){
    return{
        light:state
    }
}

function mapDispatchToProps(dispatch){
    return{
        actions : bindActionCreators(LightActions,dispatch)
    }
}

// 声明 connect 连接
App = connect(mapStateToProps,mapDispatchToProps)(App);

// 真正的连接
render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('demo')
)

这里使用 react-redux 提供 connect 的方法 链接React组件和Redux类:

// 声明 connect 连接
App = connect(mapStateToProps,mapDispatchToProps)(App);
  • connect 方法不会改变原来的组件类,反而返回一个新的 已与 Redux store 连接的 组件类。注意这里并没有注入store 对象,真正 store 对象的注入靠最后的 <Provider store>组件;(更多说明请参考 [react-redux 的 API][1])
  • 传入 connect 的 mapStateToProps方法 ,正如其名,是将 Redux 的状态 映射到 React组件的props属性。任何时候,**只要 Redux store 发生改变,mapStateToProps 函数就会被调用**。这里返回对象是 {light:state},这样确保 Redux 中的 state 发生改变时,组件的 props.light 都是最新的 Redux state。
  • mapDispatchToProps方法 则是将 Store 中的 dispatch方法 直接封装成对象的一个属性,一般会用到 Redux 的辅助函数 bindActionCreators();这里将 dispatch 绑定到 action属性,这样在红绿灯组件内让其变成红灯的时候,不需要 dispatch(changeRed()) 这么调用,直接使用 actions.changeRed(),语义化更好;(更多说明请参考 [react-redux 的 API][1])
  • 最后的 <Provider store> 使组件层级中的 connect() 方法都能够获得 Redux store,这里才真正注入store变量,之前的只是声明而已(之前的好比store是个形参,到了这一步store就是实参了)。(更多说明请参考 [react-redux 的 API][1])

经过上面的语句,Redux就将 state属性 、 (**store** 的) dispatch方法 与 R
eact 组件的 props 绑定在一起,凡是更改 redux 的 states,就会更新所连接组件的 props 属性。

react-redux 中的 connect 方法就算是HOC(High Order Component,高阶组件)了,具体原理可参考文章 初识React中的High Order Component,这是因为如果使用ES6 写React组件的话,mixin是不支持的
,因此使用High Order Component代替;

2.4、利用redux驱动react

理解了最为困难的部分,之后的事情就水到渠成了;

现在,只要记住 在App中可以直接使用Redux中的一切了 就行了

我们回过头来,完善 App 组件的代码,完善 autoChange方法:


...

class App extends Component{
    _bind(...methods){
        methods.forEach((method)=>this[method] = this[method].bind(this));
    }
    constructor(){
        super();
        this._bind('changeColor','handleClick','autoChange');
        this.state = {
            count : 0,
            timeId : null
        }
    }
    changeColor(light,actions){ // 红路灯变换规则
        switch(light.color){
            case 'red':
                actions.changeGreen();
                break;
            case 'green':
                actions.changeYellow();
                break;
            case 'yellow':
                actions.changeRed();
                break;
            default:
                actions.changeRed();
        }
    }
    autoChange(){ // 自动更改红绿灯
        const { light, actions } = this.props;
        let _self = this;

        let curCount = ++this.state.count;

        // console.log('xx,',curCount);
        if(this.state.count > +light.time){
            curCount = 0;
            this.changeColor(light,actions);
        }
        // 自动更改
        this.state.timeId = setTimeout(function(){
            _self.setState({count:curCount});
            _self.autoChange();
        },1000);

    }
    handleClick(e){  // 用点击模拟红路灯

        if(this.state.timeId){
            clearTimeout(this.state.timeId);
        } else {
            this.autoChange();
        }

    }
    render(){
        // 通过connect 注入 redux 的 dispatch 方法
        const { light, actions } = this.props;
        return (
            <div id="traffic" onClick={this.handleClick.bind(this)}>
                <Light light={light}/>
            </div>
        )
    }
}

...

至此已经完成本节示例,通过 npm start 开启服务, 在 http://localhost:3000/light/redux 中查看。

在这个示例里,通过点击红绿灯,每隔若干秒红绿灯就会变换颜色,这说明两者已经链接起来;

(这个是gif图,如果没动画请点击在新窗口打开)

在后一篇文章,将示例如何处理多个Redux、React的情形;

[1] http://camsong.github.io/redux-in-chinese/docs/react-redux/api.html

时间: 2024-08-30 14:56:18

Redux教程2:链接React的相关文章

Redux教程1:环境搭建,初写Redux

[序] 如果将React比喻成士兵的话,你的程序还需要一位将军,去管理士兵(的状态),而Redux恰好是一位好将军,简单高效: 相比起React的学习曲线,Redux的稍微平坦一些:本系列教程,将以"红绿灯"为示例贯穿整个demo,希望能让用户快速理解&学习Redux: 强烈推荐 Redux 中文文档,本redux教程所有的材料和思路都来源于此: 这个系列拆分成3篇文章,最后获得的效果图为: (这个是gif图,如果没动画请点击在新窗口打开) 红绿灯初始状态是 绿灯5s,继而循环

Redux教程3:添加倒计时

前面的教程里面,我们搭建了一个简单红绿灯示例,通过在console输出当面的倒计时时间:由于界面上不能显示倒计时,用户体验并不良好,本节我们就添加一个简单的倒计时改善一下. 作为本系列的最后一篇文章,将示例如何处理多个Redux.React的情形: 1.创建Counter类 我们定义倒计时的类名为 Counter ,创建所需要的文件(夹): mkdir actions/counter reducers/counter stores/counter components/counter views

FW MX 2004教程(10):链接设置

教程|链接 在Fireworks中,为图像设置链接区域是靠"切片"或"热点"工具来完成,因此"切片"或"热点"区域又被称为链接区域.它们不是以图像的形式存在,而是在图像导出成网页格式后,以HTML代码的形式出现. 1.切片与热点 网页层:所有的"切片"和"热点"区域都被保存在"层"面板中的"网页层"内,以划分它们与图像层的区别.但同时也可以像对待图

使用Redux管理你的React应用

React是最好的前端库,因为其发源于世界上最好的后端语言框架. -信仰 4.0 will likely be the last major release. Use Redux instead. It's really great. -Flummox框架作者 acdliteAndrew Clark 为什么使用React还需要使用别的框架来搭配? React的核心是使用组件定义界面的表现,是一个View层的前端库,那么在使用React的时候我们通常还需要一套机制去管理组件与组件之间,组件与数据模

ASP入门教程-内容链接组件

内容链接组件(Content Linking) 用于创建管理 URL 列表的内容链接 (NextLink )对象,通过该对象可以自动生成和更新目录表及先前和后续的 Web 页的导航链接.使用内容链接组件的步骤如下: 1) 创建内容链接(NextLink) 对象实例: 2) 创建内容链接列表文件: 3) 使用内容链接( NextLink) 对象的方法生成导航链接. 1.创建内容链接对象实例 内容链接组件包含在 nextlink.dll 文件中.使用内容链接组件时,首先基于该组件创建一个内容链接(

WEB标准教程:链接和文本标签的应用

我们都知道网页的最大特性是"链接",是的这个在我们现在看起来习以为常的东西,让我们的生活发生了巨大的变化,是这个小小的标签成就了这个世界上无数的互联网天才.那么让我们看看这个标签的真面目: <a href="URL" >文本区</a> ,就是这个简单的标签,其实大家都在使用,用Dreamweaver可以很简单的添加链接.但是尽管如此我们还是需要知道A的属性是什么,这样才能更好的利用它.A是个内联标签,也就是说它本身并不会产生分行.他是流于文本

AngularJS入门教程之链接与图片模板详解_AngularJS

这一步,你会为手机列表的手机添加缩略图以及一些链接,不过这些链接还不会起作用.接下来你会使用这些链接来分类显示手机的额外信息. 请重置工作目录: git checkout -f step-6 现在你应该能够看到列表里面手机的图片和链接了. 步骤5和步骤6之间最重要的不同在下面列出.你可以在GitHub里看到完整的差别. 数据 注意到现在phones.json文件包含了唯一标识符和每一部手机的图像链接.这些url现在指向app/img/phones/目录. app/phones/phones.js

React 入门实例教程

现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑. React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设 Instagram 的网站.做出来以后,发现这套东西很好用,就在2013年5月开源了. 由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单.所以,越

React+Redux打造“NEWS EARLY”单页应用 一步步让你理解最前沿技术栈的真谛

之前写过一篇文章,分享了我利用闲暇时间,使用React+Redux技术栈重构的百度某产品个人中心页面.您可以参考这里,或者参考Github代码仓库地址. 这个工程实例中,我采用了厂内的工程构建工具-FIS,并贯穿了react+redux基本思想. 今天这篇文章给大家分享一个更加复杂,但是非常有趣的一个项目- News Early单页应用. 我把这个项目所有代码托管在了我个人Github之中,感兴趣的读者可以跟我探讨. 最近我发现,React Redux生态圈项目活跃.但是作品质量"良莠不齐&qu