理解React反向数据流

在React中数据传递是按组件一级一级传递的,因为这样可以很清楚数据的流向,但也会造成一个问题,就是当用户在深层的组件中输入数据,程序取得用户数据后,无法在当前组件中传递数据到其它层级组件,而只能通过把数据回传上级组件来把数据传递到其它组件(反向数据流)

4 min read
By myfreax
理解React反向数据流

在React中数据传递是按组件一级一级传递的,因为这样可以很清楚数据的流向,但也会造成一个问题,就是当用户在深层的组件中输入数据,程序取得用户数据后,无法在当前组件中传递数据到其它层级组件,而只能通过把数据回传上级组件来把数据传递到其它组件(反向数据流),React这样做的好处就是让数据流向一直保持清晰可见,下面的Todo list就可以很好的理解这一点

Add TodoList.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Product</title>
    <script src="build/lib/react.js"></script>
    <script src="build/lib/react-dom.js"></script>
    <script src="build/lib/browser.min.js"></script>
    <script src="build/lib/jquery.min.js"></script>
    <script src="build/lib/marked.min.js"></script>
</head>
<body>
    <div id="todolist">

    </div>
</body>
<script src="build/TodoList/Row.js" type="text/javascript"></script>
<script src="build/TodoList/List.js" type="text/javascript"></script>
<script src="build/TodoList/TodoForm.js" type="text/javascript"></script>
<script src="build/TodoList/TodoList.js" type="text/javascript"></script>
</html>

TodoList组件

/**
 * Created by huangyanxiong on 16-3-11.
 */
var TodoList = React.createClass({
    /**
     * 初始化数据
     * @returns {{todo: string}}
     */
    getInitialState: function () {
      return {todos:[],todo:''};
    },
    /**
     *  处理下一级组件上传的值,即处理反向数据流
     */
    handleTodoSubmit: function (todo) {
        this.state.todos.push(todo);    //取得用户输入的数据并且推进的todos数组中
        this.setState(this.state.todos);    //设置状态,更新组件
    },
    render: function () {
        return (
            <div className="todoList">
                <h1>TODO</h1>
                <TodoForm handletodosubmit={this.handleTodoSubmit}/>
                <List todos={this.state.todos}/>
            </div>
        );
    }
});
ReactDOM.render(<TodoList/>,document.getElementById('todolist'));

List

var List = React.createClass({
    render: function () {
        var rows = this.props.todos.map(function (todo) {
            return <Row todo={todo} key={todo}/>

        });
        return (
            <ul className="list">
                {rows}
            </ul>
        );
    }
});

Row组件

/**
 * Created by huangyanxiong on 16-3-11.
 */
var Row = React.createClass({
    render: function () {
        return (
            <li>
                {this.props.todo}
            </li>
        );
    }
});

TodoForm组件

/**
 * Created by huangyanxiong on 16-3-11.
 */
var TodoForm = React.createClass({
    handleSubmit: function (e) {
        e.preventDefault();
        /**
         * 数据反向流入口,传递数据到上级组件
         * 取得用户输入的表单值,接着需要把放在list中
         * 由于React数据传递是一级一级传递的,所以只能把数据传递上级组件TodoList,然后由TodoList传递给 List
         * List组件才能接收到用户添加的Todo,并添加到List组件
         * 这就是反向数据流 TodoForm > TodoList
         * 当用户点击添加Add事件,整个数据流向
         * TodoForm > TodoList > List > Row
         */
        if (!this.refs.todo.value){
            alert('todo is not null');
            return false;
        }
        this.props.handletodosubmit(this.refs.todo.value.toString());
        this.refs.todo.value = '';
    },
    render: function () {
        return (
            <form onSubmit={this.handleSubmit}>
                <input type="text" ref="todo"/>
                <button>Add #3</button>
            </form>
        )
    }
});

在这个Todo list划分了四个组件分别是TodoList,List,Row,TodoForm

初始化时的数据流

在组件初始化渲染时可以很清晰的看到React数据时一级一级传递

TodoList > List > Row

在这时程序是不能取得用户输入的数据的,这只是一个静态版本todo list,当用户在TodoForm组件中数据并通过onSubmit事件取得用户数据,会发现数据不能在TodoForm组件中传递到List组件,为了解决这个问题,React也就引入另一个概念:反向数据流

用户提交时数据流

TodoForm > TodoList

TodoForm组件数据回传TodoList,在TodoList组件中使用this.setState(this.state.todos)更新组件,从而使数据可以传递到其它组件,来达到数据双向绑定

TodoForm > TodoList > List > Row

而对于Angular框架的双向绑定,$scopeController以及模板的数据双向绑定,对于我们来说透明的,隐藏了复杂性,可以少做很多工作,React则没有这么做,但是让我们很好的理解应用是怎么工作的