个人博客

A web front-end programmer's personal blog.

React数据传递和动画的使用及示例

React入门教程

React 是 facebook 开发的一款前端js库,入门使用教程请参考这里

React 的数据传递

React不同于Angular(双向数据绑定),是单向数据绑定,使得数据的流向更加清楚明确,但随着组件的细分,组件与组件之间的通讯数据传递是一个比较有趣的问题。通常 React 组件之间交流的方式,可以分为以下 3 种:

  • 【父组件】向【子组件】传值;
  • 【子组件】向【父组件】传值;
  • 没有任何嵌套关系的组件之间传值(PS:比如:兄弟组件之间传值)

这里简单写了几个示例,简单说明了组件之间的数据传递,示例代码地址

父组件向子组件传值

这是最常见的,也是 React 正常开发中的常见场景,主要是利用 props 来进行交流。示例代码对应 src/todo-learning.js

//父组件
var Todo = React.createClass({
    getInitialState : function(){
        ...
    },
    render : function(){
        return (
            <div className="todo-box">
                <div className="input-box">
                    <input type="text" ref="myTextInput" placeholder="请输入" onKeyUp={this.keyupHander}/>
                </div>
                <ItemList listWords={this.state.listWords}/>
            </div>
        )
    },
    keyupHander: function(ev){
        ...
    }
});
//子组件
var ItemList = React.createClass({
    getInitialState : function(){
        return {
            listData : this.props.listWords
        }
    },
    render : function(){
        var \_this = this;
        return (
            <ul className="list-box">
                {
                    this.state.listData.map(function(json,key){
                        return (
                            <li className="list-item" key={key}>
                                <span className="list-txt">{json.text}</span>
                                <a href="javascript:;" data-id={json.id} onClick={_this.deleteItem}>删除</a>
                            </li>
                        )
                    })
                }
            </ul>
        )
    },
    deleteItem : function(ev){
        ...
    }
});

input中输入的内容,通过 keyupHander传递到组件的 state中,子组件ItemList,通过添加属性listWords来向其内部传递数据,在其组件内部,通过 props 属性获取到。

注意:在循环数据时,必须给每项添加key属性,否则会有警告

子组件向父组件传值

React 为单向数据传递,子组件向父组件进行反向数据传递,可以通过,在子组件上绑定props属性,该属性是一个方法,通过该方法的参数,来进行数据的传递,示例代码对应 src/todo-todo.js

//父组件
var Todo = React.createClass({
    getInitialState : function(){
        return {
            'todos' : []
        }
    },
    render : function(){
        return (
            <div className="todo-box">
                <InputText todoInput={this.todoHander}/>  // 通过todoInput函数的参数,传递到父组件
                <ListBox todos={this.state.todos}/>
            </div>
        )
    },
    todoHander : function(todo){
        ...
    }
});
//子组件
var InputText = React.createClass({
    render : function(){
        return (
            <div className="input-box">
                <input type="text" placeholder="请输入" onKeyUp={this.inputHander}/>
            </div>
        )
    },
    inputHander : function(ev){
        ...
            //通过 props 的函数参数 实现反向数据传递
            this.props.todoInput(json);
        ...
    }
});

没有任何嵌套关系的组件之间传值

这种组件之间的数据传递可以借助pubsub.js这个库来实现,该库有两个方法,PubSub.subscribe订阅事件和PubSub.publish发布事件,通过在需要变化的组件中订阅一个事件,其他组件中通过发布该事件来变化该组件,示例代码对应 src/todo-adon.js

//父组件
var Todo = React.createClass({
    render : function(){
        return (
            <div className="todo-box">
                <InputText />
                <ListBox />
            </div>
        )
    },
});
//子组件
var InputText = React.createClass({
    render : function(){
        return (
            <div className="input-box">
                <input type="text" placeholder="请输入" onKeyUp={this.inputHander}/>
            </div>
        )
    },
    inputHander : function(ev){
        ...
            PubSub.publish('addTodo', json);
        ...
    }
});
//子组件
var ListBox = React.createClass({
    getInitialState : function(){
        return {
            listTodo : []
        }
    },
    render : function(){
        ...
    },
    //订阅事件监听数据变化
    componentDidMount : function(){
        this.pusAdd = PubSub.subscribe('addTodo',function(key,item){
            this.state.listTodo.push(item);
            this.setState({
                listTodo : this.state.listTodo
            })
        }.bind(this));
        //组件自己 订阅事件
        this.pubDel = PubSub.subscribe('delTodo',function(key,item){
            var arr = this.state.listTodo
            $.each(arr,function(index,json){
                if(json && json.id == item){
                    arr.splice(index,1)
                }
            });
            this.setState({
                listTodo : arr
            });
        }.bind(this));
    },
    //组件卸载时清除订阅事件
    componentWillUnmount : function(){
        PubSub.unsubscribe(this.pusAdd);
        PubSub.unsubscribe(this.pubDel);
    },
    deleteItem: function(ev){
        var id = $(ev.target).attr('data-id');
        //组件自己 发送事件
        PubSub.publish('delTodo', id);
    }
});

注意:pubsub订阅事件需要在组件渲染完再进行订阅(componentDidMount中),组件卸载时也要对订阅事件进行销毁

更多关于React数据传递在segmentfault中有一篇更详细的说明,点击这里

React中的Animate

React为动画提供一个ReactTransitonGroup插件组件作为一个底层的API,一个ReactCSSTransitionGroup来简单地实现基本的CSS动画和过渡。这个的灵感来自于优秀的ng-animate库。示例代码对应 src/todo-animate.js

React的Animate使用需要引入带有插件的React库 react-with-addons.js,参考todo-animate.html

ReactTransitonGroup组动画必须要挂载了才能生效,简单说不能放在动态变化的结构中。如下:

...
var item = this.state.listTodo.map(function(json,key){
    return (
        <li className="list-item" key={key}><span className="list-txt">{json.todo} </span><a href="javascript:;" data-id={json.id} onClick={this.deleteItem}>删除</a></li>
    )
}.bind(this));
...
<ul className="list-box">
    <ReactCSSTransitionGroup transitionName="slide" transitionEnterTimeout={0} transitionLeaveTimeout={0}>
      {item}
    </ReactCSSTransitionGroup>
</ul>

代码中{item},是会变化的,因此ReactCSSTransitionGroup,不能放在其中,需要放在外面,作为固定的一种结构,另外 transitionEnterTimeout和transitionLeaveTimeout属性需要设置否则会有警告。

注意:你必须为ReactCSSTransitionGroup的所有子级提供键属性,即使只渲染一项。这就是React确定哪一个子级插入了,移除了,或者停留在那里。同之前的key

结束

希望通过本文能帮助更快的上手开发React项目,更多文档介绍请转至React