React简介

Why React
React是Facebook开发的一款JS库。在React的官网上通过《Why did we build React?》了解到以下四点:
1、React不是一个MVC框架
React是一个构造可组合式用户界面的库。它鼓励创建可重用的UI组件显示会随着时间而改变的数据。
2、React不使用模板
传统上,web应用UI使用模板或者html指令构造。这些模板规定一套完整的抽象使程序员可以去构建自己的UI。
不同的是,React处理构建用户界面通过将他们分解成组件。这意味着,React使用一个真正的、全功能的编程语言去渲染视图,我们可以看到作为一个优势模板的一些原因:
a. JavaScript是一个灵活的强大的编程语言,具有构建抽象的能力。在一个大型应用中这 是非常重要的。
b. 通过统一相应的视图逻辑标签,React可以使构建的视图更容易扩展和维护。
c. 通过整合标签和内容到JavaScript,不需要手动连接字符串因此可以减少XSS漏洞面积。
3、响应式更新非常简单
React真正的亮点是数据随时间改变。
在一个传统的JavaScript应用中,需要考虑数据的变化然后指示DOM做出变化使其保持最新。甚至AngularJS,提供一个声明式接口经由指令和数据绑定请求一个关联的函数去手动的更新DOM节点。
React采用不同的方法。
当组件第一次初始化时,render方法被调用,为视图生成一个轻量级的表现。通过这个表现,产生一个标签字符串,然后插入到文档中。当数据变化时,render方法再次被调用。为了尽可能有效的完成更新,我们比较之前调用render返回的值与新的值,然后产生一个最小限度的变更去应用到DOM中。
render返回的数据既不是一个字符串也不是一个DOM节点。它是一个轻量级的类型,描述DOM应该是什么样的。
因为这个重新渲染是非常快的(TodoMVC1毫秒左右),开发者不需要明确的指定数据绑定。这个方法更容易去构建应用程序。
4、HTML5仅仅是个开始
因为React有自己轻量级的文档表现,因此可以用它实现以下内容:
1.Facebook动态表格可以通过<canvas>渲染取代HTML。
2.Instagram是一个'single page'网页应用完全由React和Backbone.Router构建的。设计者可以像通常一样使用JSX编写React代码。
3.可以构建内部的应用雏形运行React在一个web工作站上,使用React去驱动本地ios视图通过一个objective桥。
4.可以运行React在服务器上,便于SEO、性能、代码分享和项目灵活性。
5.事件在全部现代浏览器(包括IE8)下表现一致性还有符合标准化,并且自动使用事件委派。


创造React是为了解决一个问题:构建随着时间数据不断变化的大规模应用程序。


使用Reactk框架需要在官网下载相关文件,官网地址:http://reactjs.cn/react---版本:react-0.14.7
--------------------------------------------------------------------------------------------------------------------
示例:在网页中显示输出“Hello World”
<!DOCTYPE html>
<html>
  <head>
    <script src="build/react.js"></script>
    <script src="build/JSXTransformer.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/jsx">
      React.render(
        <h1>Hello, world!</h1>,
        document.getElementById('example')
      );
    </script>
  </body>
</html>
数据呈现
示例:输入框中输入姓名并保留,右侧当前时间显示不会受到影响。
<body>
<div id="example"></div>
<script type="text/jsx">
    var HelloWorld = React.createClass({
        render: function() {
            return (
                    <p>
                        Hello, <input type="text" placeholder="Your name here" />!
                        It is {this.props.date.toTimeString()}
                    </p>
            );
        }
    });
    setInterval(function() {
        React.render(
                <HelloWorld date={new Date()} />,
                document.getElementById('example')
        );
    }, 500);
</script>
<script src="../React/react.js"></script>
<script src="../React/JSXTransformer.js"></script>
</body>
注意:
1.React 组件只能渲染单个根节点。如果你想要返回多个节点,它们必须被包含在同一个节点里。
2.在组件里这些属性是不可直接改变的,也就是说 this.props 是只读的。
3.可以设置相关CSS样式,引入时需注意格式。<link rel="stylesheet" href="../css/index.css"/>


没有jsx的React
1.你完全可以选择是否使用 JSX,并不是 React 必须的。你可以通过 React.createElement 来创建一个树。
第一个参数是标签,第二个参数是一个属性对象,第三个是子节点。
var child = React.createElement('li', null, 'Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child);
React.render(root, document.body);


2.方便起见,你可以创建基于自定义组件的速记工厂方法。
var Factory = React.createFactory(ComponentClass);
...
var root = Factory({ custom: 'prop' });
React.render(root, document.body);


3.React 已经为 HTML 标签提供内置工厂方法。
var root = React.DOM.ul({ className: 'my-list' },
             React.DOM.li(null, 'Text Content')
           );


交互界面
示例:鼠标点击文字后变为另外的文字
<body>
<div id="example"></div>
<script type="text/jsx">
    var LikeButton = React.createClass({
    getInitialState: function() {
        return {liked: false};
    },
    handleClick: function(event) {
        this.setState({liked: !this.state.liked});
    },
    render: function() {
        var text = this.state.liked ? 'like' : 'haven\'t liked';
        return (
            <p onClick={this.handleClick}>
                You {text} this. Click to toggle.
            </p>
        );
    }
});


React.render(
    <LikeButton />,
    document.getElementById('example')
);
</script>
<script src="../React/react.js"></script>
<script src="../React/JSXTransformer.js"></script>
</body>
1.事件处理与合成事件
React 里只需把事件处理器(event handler)以骆峰命名(camelCased)形式当作组件的 props 传入即可,就像使用普通 HTML 那样。React 内部创建一套合成事件系统来使所有事件在 IE8 和以上浏览器表现一致。也就是说,React 知道如何冒泡和捕获事件,而且你的事件处理器接收到的 events 参数与 W3C 规范 一致,无论你使用哪种浏览器。


如果需要在手机或平板等触摸设备上使用 React,需要调用 React.initializeTouchEvents(true); 启用触摸事件处理。


2.自动绑定和事件代理
Autobinding: 在 JavaScript 里创建回调的时候,为了保证 this 的正确性,一般都需要显式地绑定方法到它的实例上。有了 React,所有方法被自动绑定到了它的组件实例上。React 还缓存这些绑定方法,所以 CPU 和内存都是非常高效。而且还能减少打字!


事件代理 : React 实际并没有把事件处理器绑定到节点本身。当 React 启动的时候,它在最外层使用唯一一个事件监听器处理所有事件。当组件被加载和卸载时,只是在内部映射里添加或删除事件处理器。当事件触发,React 根据映射来决定如何分发。当映射里处理器时,会当作空操作处理。


3.组件其实是状态机
React 把用户界面当作简单状态机。把用户界面想像成拥有不同状态然后渲染这些状态,可以轻松让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。React 来决定如何最高效地更新 DOM。


4.State 工作原理
常用的通知 React 数据变化的方法是调用 setState(data, callback)。这个方法会合并(merge) data 到 this.state,并重新渲染组件。渲染完成后,调用可选的 callback 回调。大部分情况下不需要提供 callback,因为 React 会负责把界面更新到最新状态。


5.哪些组件应该有 State?
大部分组件的工作应该是从 props 里取数据并渲染出来。但是,有时需要对用户输入、服务器请求或者时间变化等作出响应,这时才需要使用 State。
** 尝试把尽可能多的组件无状态化。** 这样做能隔离 state,把它放到最合理的地方,也能减少冗余,同时易于解释程序运作过程。
常用的模式是创建多个只负责渲染数据的无状态(stateless)组件,在它们的上层创建一个有状态(stateful)组件并把它的状态通过 props 传给子级。这个有状态的组件封装了所有用户的交互逻辑,而这些无状态组件则负责声明式地渲染数据。


6.哪些 应该 作为 State?
State 应该包括那些可能被组件的事件处理器改变并触发用户界面更新的数据。 真实的应用中这种数据一般都很小且能被 JSON 序列化。当创建一个状态化的组件时,想象一下表示它的状态最少需要哪些数据,并只把这些数据存入 this.state。在 render() 里再根据 state 来计算你需要的其它数据。你会发现以这种方式思考和开发程序最终往往是正确的,因为如果在 state 里添加冗余数据或计算所得数据,需要你经常手动保持数据同步,不能让 React 来帮你处理。


7.哪些 不应该 作为 State?
this.state 应该仅包括能表示用户界面状态所需的最少数据。因此,它不应该包括:
a. 计算所得数据: 不要担心根据 state 来预先计算数据 —— 把所有的计算都放到 render() 里更容易保证用户界面和数据的一致性。例如,在 state 里有一个数组(listItems),我们要把数组长度渲染成字符串, 直接在 render() 里使用 this.state.listItems.length + ' list items' 比把它放到 state 里好的多。
b. React 组件: 在 render() 里使用当前 props 和 state 来创建它。
c. 基于 props 的重复数据: 尽可能使用 props 来作为惟一数据来源。把 props 保存到 state 的一个有效的场景是需要知道它以前值的时候,因为未来的 props 可能会变化。


复合组件
示例:Facebook Graph API 开发显示个人图片和用户名的 Avatar 组件
<body>
<div id="example"></div>
<script type="text/jsx">
 var Avatar = React.createClass({
    render: function() {
        return (
            <div>
                <ProfilePic username={this.props.username} />
                <ProfileLink username={this.props.username} />
            </div>
        );
    }
});


var ProfilePic = React.createClass({
    render: function() {
        return (
            <img src={'../css/img/QQpicture' + this.props.username + '/picture'} />
        );
    }
});


var ProfileLink = React.createClass({
    render: function() {
        return (
            <a href={'http://d.weibo.com/' + this.props.username}>       //文字链接
                {this.props.username}
            </a>
        );
    }
});


React.render(
    <Avatar username="SQ" />,
    document.getElementById('example')
);
</script>
<script src="../React/react.js"></script>
<script src="../React/JSXTransformer.js"></script>
</body>
1.从属关系
上面例子中,Avatar 拥有 ProfilePic 和 ProfileLink 的实例。拥有者 就是给其它组件设置 props 的那个组件。更正式地说, 如果组件 Y 在 render() 方法是创建了组件 X,那么 Y 就拥有 X。上面讲过,组件不能修改自身的 props - 它们总是与它们拥有者设置的保持一致。这是保持用户界面一致性的关键性原则。
把从属关系与父子关系加以区别至关重要。从属关系是 React 特有的,而父子关系简单来讲就是DOM 里的标签的关系。在上一个例子中,Avatar 拥有 div、ProfilePic 和 ProfileLink 实例,div 是 ProfilePic 和 ProfileLink 实例的父级(但不是拥有者)。


2.子级
实例化 React 组件时,你可以在开始标签和结束标签之间引用在React 组件或者Javascript 表达式:
<Parent><Child /></Parent>
Parent 能通过专门的 this.props.children props 读取子级。this.props.children 是一个不透明的数据结构: 通过 React.Children 工具类 来操作。


3.子级校正(Reconciliation)
校正就是每次 render 方法调用后 React 更新 DOM 的过程。 一般情况下,子级会根据它们被渲染的顺序来做校正。例如,下面代码描述了两次渲染的过程:
// 第一次渲染
<Card>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</Card>
// 第二次渲染
<Card>
  <p>Paragraph 2</p>
</Card>
直观来看,只是删除了<p>Paragraph 1</p>。事实上,React 先更新第一个子级的内容,然后删除最后一个组件。React 是根据子级的顺序来校正的。


4.子组件状态管理
对于大多数组件,这没什么大碍。但是,对于使用 this.state 来在多次渲染过程中里维持数据的状态化组件,这样做潜在很多问题。
多数情况下,可以通过隐藏组件而不是删除它们来绕过这些问题。
// 第一次渲染
<Card>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</Card>
// 第二次渲染
<Card>
  <p style={{display: 'none'}}>Paragraph 1</p>
  <p>Paragraph 2</p>
</Card>


5.动态子级
如果子组件位置会改变(如在搜索结果中)或者有新组件添加到列表开头(如在流中)情况会变得更加复杂。如果子级要在多个渲染阶段保持自己的特征和状态,在这种情况下,你可以通过给子级设置惟一标识的 key 来区分。
  render: function() {
    var results = this.props.results;
    return (
      <ol>
        {results.map(function(result) {
          return <li key={result.id}>{result.text}</li>;
        })}
      </ol>
    );
  }
当 React 校正带有 key 的子级时,它会确保它们被重新排序(而不是破坏)或者删除(而不是重用)。 务必 把 key 添加到子级数组里组件本身上,而不是每个子级内部最外层 HTML 上:
// 错误!
var ListItemWrapper = React.createClass({
  render: function() {
    return <li key={this.props.data.id}>{this.props.data.text}</li>;
  }
});
var MyComponent = React.createClass({
  render: function() {
    return (
      <ul>
        {this.props.results.map(function(result) {
          return <ListItemWrapper data={result}/>;
        })}
      </ul>
    );
  }
});


// 正确 :)
var ListItemWrapper = React.createClass({
  render: function() {
    return <li>{this.props.data.text}</li>;
  }
});
var MyComponent = React.createClass({
  render: function() {
    return (
      <ul>
        {this.props.results.map(function(result) {
           return <ListItemWrapper key={result.id} data={result}/>;
        })}
      </ul>
    );
  }
});
也可以传递 object 来做有 key 的子级。object 的 key 会被当作每个组件的 key。但是一定要牢记 JavaScript 并不总是保证属性的顺序会被保留。实际情况下浏览器一般会保留属性的顺序,除了 使用 32位无符号数字做为 key 的属性。数字型属性会按大小排序并且排在其它属性前面。一旦发生这种情况,React 渲染组件的顺序就是混乱。可能在 key 前面加一个字符串前缀来避免:
  render: function() {
    var items = {};


    this.props.results.forEach(function(result) {
      // 如果 result.id 看起来是一个数字(比如短哈希),那么
      // 对象字面量的顺序就得不到保证。这种情况下,需要添加前缀
      // 来确保 key 是字符串。
      items['result-' + result.id] = <li>{result.text}</li>;
    });


    return (
      <ol>
        {items}
      </ol>
    );
  }


6.数据流
React 里,数据通过上面介绍过的 props 从拥有者流向归属者。这就是高效的单向数据绑定(one-way data binding):拥有者通过它的 props 或 state 计算出一些值,并把这些值绑定到它们拥有的组件的 props 上。因为这个过程会递归地调用,所以数据变化会自动在所有被使用的地方自动反映出来。


可复用组件
设计接口的时候,把通用的设计元素(按钮,表单框,布局组件等)拆成接口良好定义的可复用的组件。这样,下次开发相同界面程序时就可以写更少的代码,也意义着更高的开发效率,更少的 Bug 和更少的程序体积。


1.Prop 验证
随着应用不断变大,保证组件被正确使用变得非常有用。为此我们引入 propTypes。React.PropTypes 提供很多验证器 (validator) 来验证传入数据的有效性。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。注意为了性能考虑,只在开发环境验证 propTypes。下面用例子来说明不同验证器的区别:
React.createClass({
  propTypes: {
    // 可以声明 prop 为指定的 JS 基本类型。默认
    // 情况下,这些 prop 都是可传可不传的。
    optionalArray: React.PropTypes.array,
    optionalBool: React.PropTypes.bool,
    optionalFunc: React.PropTypes.func,
    optionalNumber: React.PropTypes.number,
    optionalObject: React.PropTypes.object,
    optionalString: React.PropTypes.string,


    // 所有可以被渲染的对象:数字,
    // 字符串,DOM 元素或包含这些类型的数组。
    optionalNode: React.PropTypes.node,


    // React 元素
    optionalElement: React.PropTypes.element,


    // 用 JS 的 instanceof 操作符声明 prop 为类的实例。
    optionalMessage: React.PropTypes.instanceOf(Message),


    // 用 enum 来限制 prop 只接受指定的值。
    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),


    // 指定的多个对象类型中的一个
    optionalUnion: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.number,
      React.PropTypes.instanceOf(Message)
    ]),


    // 指定类型组成的数组
    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),


    // 指定类型的属性构成的对象
    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),


    // 特定形状参数的对象
    optionalObjectWithShape: React.PropTypes.shape({
      color: React.PropTypes.string,
      fontSize: React.PropTypes.number
    }),


    // 以后任意类型加上 `isRequired` 来使 prop 不可空。
    requiredFunc: React.PropTypes.func.isRequired,


    // 不可空的任意类型
    requiredAny: React.PropTypes.any.isRequired,


    // 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接
    // 使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
    customProp: function(props, propName, componentName) {
      if (!/matchme/.test(props[propName])) {
        return new Error('Validation failed!');
      }
    }
  },
  /* ... */
});
2.默认 Prop 值
React 支持以声明式的方式来定义 props 的默认值。
var ComponentWithDefaultProps = React.createClass({
  getDefaultProps: function() {
    return {
      value: 'default value'
    };
  }
  /* ... */
});
当父级没有传入 props 时,getDefaultProps() 可以保证 this.props.value 有默认值,注意 getDefaultProps 的结果会被 缓存。得益于此,你可以直接使用 props,而不必写手动编写一些重复或无意义的代码。


3.传递 Props:小技巧
有一些常用的 React 组件只是对 HTML 做简单扩展。通常,你想少写点代码来把传入组件的 props 复制到对应的 HTML 元素上。这时 JSX 的 spread 语法会帮到你:
var CheckLink = React.createClass({
  render: function() {
    // 这样会把 CheckList 所有的 props 复制到 <a>
    return <a {...this.props}>{'√ '}{this.props.children}</a>;
  }
});


React.render(
  <CheckLink href="/checked.html">
    Click here!
  </CheckLink>,
  document.getElementById('example')
);


4.单个子级
React.PropTypes.element 可以限定只能有一个子级传入。
var MyComponent = React.createClass({
  propTypes: {
    children: React.PropTypes.element.isRequired
  },
  render: function() {
    return (
      <div>
        {this.props.children} // 有且仅有一个元素,否则会抛异常。
      </div>
    );
  }
});


5.Mixins
组件是 React 里复用代码最佳方式,但是有时一些复杂的组件间也需要共用一些功能。有时会被称为 跨切面关注点。React 使用 mixins 来解决这类问题。


一个通用的场景是:一个组件需要定期更新。用 setInterval() 做很容易,但当不需要它的时候取消定时器来节省内存是非常重要的。React 提供 生命周期方法 来告知组件创建或销毁的时间。下面来做一个简单的 mixin,使用 setInterval() 并保证在组件销毁时清理定时器。
var SetIntervalMixin = {
  componentWillMount: function() {
    this.intervals = [];
  },
  setInterval: function() {
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {
    this.intervals.map(clearInterval);
  }
};


var TickTock = React.createClass({
  mixins: [SetIntervalMixin], // 引用 mixin
  getInitialState: function() {
    return {seconds: 0};
  },
  componentDidMount: function() {
    this.setInterval(this.tick, 1000); // 调用 mixin 的方法
  },
  tick: function() {
    this.setState({seconds: this.state.seconds + 1});
  },
  render: function() {
    return (
      <p>
        React has been running for {this.state.seconds} seconds.
      </p>
    );
  }
});


React.render(
  <TickTock />,
  document.getElementById('example')
);
关于 mixin 值得一提的优点是,如果一个组件使用了多个 mixin,并且有多个 mixin 定义了同样的生命周期方法(如:多个 mixin 都需要在组件销毁时做资源清理操作),所有这些生命周期方法都保证会被执行到。方法执行顺序是:首先按 mixin 引入顺序执行 mixin 里方法,最后执行组件内定义的方法。


传递Props
React 里有一个非常常用的模式就是对组件做一层抽象。组件对外公开一个简单的属性(Props)来实现功能,但内部细节可能有非常复杂的实现。
可以使用 JSX 展开属性来合并现有的 props 和其它值:
return <Component {...this.props} more="values" />;
如果不使用 JSX,可以使用一些对象辅助方法如 ES6 的 Object.assign 或 Underscore _.extend。
return Component(Object.assign({}, this.props, { more: 'values' }));


表单事件


1.交互属性
表单组件支持几个受用户交互影响的属性:
value,用于 <input>、<textarea> 组件。
checked,用于类型为 checkbox 或者 radio 的 <input> 组件。
selected,用于 <option> 组件。
在 HTML 中,<textarea> 的值通过子节点设置;在 React 中则应该使用 value 代替。


表单组件可以通过 onChange 回调函数来监听组件变化。当用户做出以下交互时,onChange 执行并通过浏览器做出响应:
<input> 或 <textarea> 的 value 发生变化时。
<input> 的 checked 状态改变时。
<option> 的 selected 状态改变时。
和所有 DOM 事件一样,所有的 HTML 原生组件都支持 onChange 属性,而且可以用来监听冒泡的 change 事件。


2.受限组件
设置了 value 的 <input> 是一个受限组件。 对于受限的 <input>,渲染出来的 HTML 元素始终保持 value 属性的值。例如:
  render: function() {
    return <input type="text" value="Hello!" />;
  }
上面的代码将渲染出一个值为 Hello! 的 input 元素。用户在渲染出来的元素里输入任何值都不起作用,因为 React 已经赋值为 Hello!。如果想响应更新用户输入的值,就得使用 onChange 事件:
  getInitialState: function() {
    return {value: 'Hello!'};
  },
  handleChange: function(event) {
    this.setState({value: event.target.value});
  },
  render: function() {
    var value = this.state.value;
    return <input type="text" value={value} onChange={this.handleChange} />;
  }
上面的代码中,React 将用户输入的值更新到 <input> 组件的 value 属性。这样实现响应或者验证用户输入的界面就很容易了。例如:
  handleChange: function(event) {
    this.setState({value: event.target.value.substr(0, 140)});
  }
上面的代码接受用户输入,并截取前 140 个字符。


3.不受限组件
没有设置 value(或者设为 null) 的 <input> 组件是一个不受限组件。对于不受限的 <input> 组件,渲染出来的元素直接反应用户输入。例如:
  render: function() {
    return <input type="text" />;
  }
上面的代码将渲染出一个空值的输入框,用户输入将立即反应到元素上。和受限元素一样,使用 onChange 事件可以监听值的变化。
如果想给组件设置一个非空的初始值,可以使用 defaultValue 属性。例如:
  render: function() {
    return <input type="text" defaultValue="Hello!" />;
  }
上面的代码渲染出来的元素和受限组件一样有一个初始值,但这个值用户可以改变并会反应到界面上。
同样地, 类型为 radio、checkbox 的<input> 支持 defaultChecked 属性, <select> 支持 defaultValue 属性。
  render: function() {
      return (
          <div>
            <input type="radio" name="opt" defaultChecked /> Option 1
            <input type="radio" name="opt" /> Option 2
            <select defaultValue="C">
              <option value="A">Apple</option>
              <option value="B">Banana</option>
              <option value="C">Cranberry</option>
            </select>
          </div>
      );
    }


4.为什么使用受限组件?
在 React 中使用诸如 <input> 的表单组件时,遇到了一个在传统 HTML 中没有的挑战。
比如下面的代码:
  <input type="text" name="title" value="Untitled" />
在 HTML 中将渲染初始值为 Untitled 的输入框。用户改变输入框的值时,节点的 value 属性(property)将随之变化,但是 node.getAttribute('value') 还是会返回初始设置的值 Untitled.
与 HTML 不同,React 组件必须在任何时间点描绘视图的状态,而不仅仅是在初始化时。比如在 React 中:
  render: function() {
    return <input type="text" name="title" value="Untitled" />;
  }
该方法在任何时间点渲染组件以后,输入框的值就应该始终为 Untitled。


5.为什么 <textarea> 使用 value 属性?
在 HTML 中, <textarea> 的值通常使用子节点设置:


  <!-- 反例:在 React 中不要这样使用! -->
  <textarea name="description">This is the description.</textarea>
对 HTML 而言,让开发者设置多行的值很容易。但是,React 是 JavaScript,没有字符限制,可以使用 \n 实现换行。简言之,React 已经有 value、defaultValue 属性,</textarea> 组件的子节点扮演什么角色就有点模棱两可了。基于此, 设置 <textarea> 值时不应该使用子节点:
  <textarea name="description" value="This is a description." />
如果非要*使用子节点,效果和使用 defaultValue 一样。


6.为什么 <select> 使用 value 属性
HTML 中 <select> 通常使用 <option> 的 selected 属性设置选中状态;React 为了更方面的控制组件,采用以下方式代替:
  <select value="B">
    <option value="A">Apple</option>
    <option value="B">Banana</option>
    <option value="C">Cranberry</option>
  </select>
如果是不受限组件,则使用 defaultValue。


注意:
给 value 属性传递一个数组,可以选中多个选项:<select multiple={true} value={['B', 'C']}>。


浏览器中的工作原理


1.虚拟DOM
React是很快的,因为它从不直接操作DOM。React在内存中维护一个快速响应的DOM描述。render()方法返回一个DOM的描述,React能够利用内存中的描述来快速地计算出差异,然后更新浏览器中的DOM。


另外,React实现了一个完备的虚拟事件系统,尽管各个浏览器都有自己的怪异行为,React确保所有事件对象都符合W3C规范,并且持续冒泡,用一种高性能的方式跨浏览器(and everything bubbles consistently and in a performant way cross-browser)。你甚至可以在IE8中使用一些HTML5的事件!


大多数时候你应该呆在React的“虚拟浏览器”世界里面,因为它性能更加好,并且容易思考。但是,有时你简单地需要调用底层的API,或许借助于第三方的类似于jQuery插件这种库。React为你提供了直接使用底层DOM API的途径。


2.Refs和getDOMNode()
为了和浏览器交互,你将需要对DOM节点的引用。每一个挂载的React组件有一个getDOMNode()方法,你可以调用这个方法来获取对该节点的引用。
注意:
getDOMNode()仅在挂载的组件上有效(也就是说,组件已经被放进了DOM中)。如果你尝试在一个未被挂载的组件上调用这个函数(例如在创建组件的render()函数中调用getDOMNode()),将会抛出异常。


为了获取一个到React组件的引用,你可以使用this来得到当前的React组件,或者你可以使用refs来指向一个你拥有的组件。它们像这样工作:
var MyComponent = React.createClass({
  handleClick: function() {
    // Explicitly focus the text input using the raw DOM API.
    this.refs.myTextInput.getDOMNode().focus();
  },
  render: function() {
    // The ref attribute adds a reference to the component to
    // this.refs when the component is mounted.
    return (
      <div>
        <input type="text" ref="myTextInput" />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.handleClick}
        />
      </div>
    );
  }
});


React.render(
  <MyComponent />,
  document.getElementById('example')
);
组件生命周期
组件的生命周期包含三个主要部分:
挂载: 组件被插入到DOM中。
更新: 组件被重新渲染,查明DOM是否应该刷新。
移除: 组件从DOM中移除。
React提供生命周期方法,你可以在这些方法中放入自己的代码。我们提供will方法,会在某些行为发生之前调用,和did方法,会在某些行为发生之后调用。


1.挂载
getInitialState(): object在组件被挂载之前调用。状态化的组件应该实现这个方法,返回初始的state数据。
componentWillMount()在挂载发生之前立即被调用。
componentDidMount()在挂载结束之后马上被调用。需要DOM节点的初始化操作应该放在这里。


2.更新
componentWillReceiveProps(object nextProps)当一个挂载的组件接收到新的props的时候被调用。该方法应该用于比较this.props和nextProps,然后使用this.setState()来改变state。
shouldComponentUpdate(object nextProps, object nextState): boolean当组件做出是否要更新DOM的决定的时候被调用。实现该函数,优化this.props和nextProps,以及this.state和nextState的比较,如果不需要React更新DOM,则返回false。
componentWillUpdate(object nextProps, object nextState)在更新发生之前被调用。你可以在这里调用this.setState()。
componentDidUpdate(object prevProps, object prevState)在更新发生之后调用。


3.移除
componentWillUnmount()在组件移除和销毁之前被调用。清理工作应该放在这里。


挂载的方法
挂载的复合组件也支持如下方法:
getDOMNode(): DOMElement可以在任何挂载的组件上面调用,用于获取一个指向它的渲染DOM节点的引用。
forceUpdate()当你知道一些很深的组件state已经改变了的时候,可以在该组件上面调用,而不是使用this.setState()。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值