前端学习笔记前端学术React

React笔记

2017-02-23  本文已影响1704人  不二很纯洁

React 元素

ReactNode

ReactNode 是虚拟 DOM 的基本构建,可以是以下任意一种核心类型

ReactElement 和 ReactText 都是 ReactNode 。 一个 ReactNode 的数组称为 ReactFragment 。


创建 React 元素

React 库的入口点是 React 对象


渲染 React 元素

ReactDom.render() 将我们的 ReactNode 树渲染成 DOM

ReactDom.render(ReactElement, DOMElement, callback);

在服务器上更新 DOM

虚拟 DOM 只依赖 JavaScript ,而 Node.js 可以在服务器上运行 JavaScript ,所以我们可以在服务器端使用 React 库,并且创建 ReactNode 树。


使用 JSX 来创建 React 元素

JSX 允许我们在 JavaScript 代码中使用类似 HTML 的语法,我们可以清晰的看到渲染后的 HTML 布局结构。

var React = require('react');
var ReactDom = require('react-dom');

var listOfItems =   <ul className="list-of=items">
                        <li className="item1">item1</li>
                        <li className="item2">item2</li>
                        <li className="item3">item3</li>
                    </ul>;

ReactDom.render(listOfItems, document.getElementById('react-application'));

创建React组件

创建第一个无状态 React 组件

var React = require('react');
var ReactDom = require('react-dom');

var ReactClass = React.createClass({
    render: function(){
        return React.createElement('h1', {className: 'header'},'这是 React 组件');
    }
});

var createComponentElement = React.createElement(ReactClass);

var reacteComponent = ReactDom.render(createComponentElement, document.getElementById('react-application'));

创建第一个有状态的 React 组件

render() 函数唯一的作用是根据传递的数据返回一个 React 元素。使用 React API 有两种方法将数据传递给 render() 函数:

this.props 和 this.data 的区别:

更新组件的 state

React 提供了一个通用方式:使用 setState(data,callback) 更新 state ,这个函数有两个参数:

每当更新组件的状态时,React 都会调用组件的 render() 函数,包括所有子组件在内都会被重新渲染。事实上,每次调用 render() 函数时它都会重新渲染全部虚拟 DOM 。

       当调用 this.setState() 函数,并向它传递一个表示下一状态的数据对象时,React 将会合并下一个状态和当前状态。在合并过程中,React 会使用下一个状态覆盖当前状态。没有被覆盖的当前状态将成为下一个状态的一部分。

var React = require('react');
var ReactDom = require('react-dom');

var ReactClass = React.createClass({
    getInitialState: function(){
        return {
            isHeaderHidden: false,
            title: '有状态的 React 组件'
        };
    },

    handleClick: function(){
        this.setState({
            isHeaderHidden: !this.state.isHeaderHidden
        })
    },

    render: function(){
        var headerElement = React.createElement('h1', {className: 'header', key: 'header'}, this.state.title);
        var buttonElement = React.createElement('button', {className: 'btn btn-default', onClick: this.handleClick, key: 'button'}, '显示/隐藏');
        if(this.state.isHeaderHidden){
            return React.createElement('div', null, [buttonElement]);
        }

        return React.createElement('div', null, [headerElement, buttonElement]);
    }
});

var createComponentElement = React.createElement(ReactClass);

var reacteComponent = ReactDom.render(createComponentElement, document.getElementById('react-application'));

上面的例子中, state 中的 title 从没有改变过,这引出了一个重要的问题:我们应该在 state 中放什么?

组件的 state 应该用来存储组件的事件函数随时可能会改变的数据,以达到重新渲染并保持组件的用户界面最新的目的。

将 state 对象中组件状态保持为最小可能表示形式,并在 render() 函数中使用 state 和 props 来计算数据的其余部分。

无论在 state 中放了什么,都需要自己更新。而在 render() 函数中放入的内容都会通过 React 自动更新。

var React = require('react');
var ReactDom = require('react-dom');

var ReactClass = React.createClass({
    getInitialState: function(){
        return {
            isHeaderHidden: false
        };
    },

    handleClick: function(){
        this.setState({
            isHeaderHidden: !this.state.isHeaderHidden
        })
    },

    render: function(){
        var title = '有状态的 React 组件';

        var headerElement = React.createElement('h1', {className: 'header', key: 'header'}, title);
        var buttonElement = React.createElement('button', {className: 'btn btn-default', onClick: this.handleClick, key: 'button'}, '显示/隐藏');

        if(this.state.isHeaderHidden){
            return React.createElement('div', null, [buttonElement]);
        }

        return React.createElement('div', null, [headerElement, buttonElement]);
    }
});

var createComponentElement = React.createElement(ReactClass);

var reacteComponent = ReactDom.render(createComponentElement, document.getElementById('react-application'));

让 React 组件变得可响应

创建一个 React 组件容器

< app.js >
-----------------------------------------------------------
var React       = require('react');
var ReactDom    = require('react-dom');
var Application = require('./components/Application.react');

ReactDOM.render(<Application />, document.getElementById('react-application'));

< Application.react.js >
-----------------------------------------------------------
var React       = require('react');
var Stream      = require('./Stream.react');
var Collection  = require('./Collection.react');

var Application = React.createClass({
    getInitialState: function(){
        return {
            collectionTweets: {}
        };
    },

    addTweetToCollection: function(){
        var collectionTweets = this.state.collectionTweets;

        collectionTweets[tweet.id] = tweet;

        this.setState({
            collectionTweets: collectionTweets
        });
    },

    removeTweetsFromCollection: function(){
        var collectionTweets = this.state.collectionTweets;

        delete collectionTweets[tweet.id];

        this.setState({
            collectionTweets: collectionTweets
        });
    },

    removeAllTweetsFromCollection: function(){
        this.setState({
            collectionTweets: {}
        });
    },

    render: function(){
        return (
            <div className="container-fluid">
                <div className="row">
                    <div className="col-md-4 text-center">
                        <Stream onAddTweetToCollection={this.addTweetToCollection} />
                    </div>
                    <div className="col-md-8">
                        <Collection tweets={this.state.collectionTweets} onRemoveTweetsFromCollection={this.removeTweetsFromCollection} onRemoveAllTweetsFromCollection={this.removeAllTweetsFromCollection} />
                    </div>
                </div>
            </div>
        );
    }
});

module.exports = Application;



< Stream.react.js >
-----------------------------------------------------------
var React                = require('react');
var SnapkiteStreamClient = require('snapkite-stream-client');
var StreamTweet          = require('./StreamTweet.react');
var Header               = require('./Header.react');

var Stream = React.createClass({
    getInitialState: function(){
        return {
            tweet: null
        };
    },

    componentDidMount: function(){
        SnapkiteStreamClient.initialzeStream(this.handleNewTweet);
    },

    componentWillUnmount: function(){
        SnapkiteStreamClient.destroyStream();
    },

    handleNewTweet: function(){
        this.setState({
            tweet: tweet
        });
    },

    render: function(){
        var tweet = this.state.tweet;

        if (tweet) {
            return (
                <StreamTweet tweet={tweet} addTweetToCollection={this.props.onAddTweetToCollection} />
            );
        }

        return (
            <Header text="Waiting for public photos form Twitter..." />
        );
    }
});

module.exports = Stream;

React 组件的生命周期方法

所有 React 组件生命周期方法可以分为下面三个阶段:

用 React 的属于来说,把组件插入 DOM 叫挂载,相反在 DOM 中删除组件叫卸载。

  1. 挂载方法

    • getInitialState()
      这个方法是第一个被调用的,它会在 React 将组件插入 DOM 之前被调用。

    • componentWillMount()
      这个方法是第二个被调用的,它会在 React 将组件即将插入 DOM 时被调用。

    • componentDidMount()
      这个方法是第三个被调用的,它会在 React 将组件插入到 DOM 之后立即被调用。更新后的 DOM 现在是可以被访问,这意味着这个方法是初始化其他需要访问这些 DOM 的 JavaScript 库最佳的地方。

    React 第一次渲染时,将按顺序执行以下方法:

    • getInitialState()
    • componentWillMount()
    • render()
    • componentDidMount()

    这些方法在 React 组件的 挂载阶段 被调用。它们仅执行一次,除非我们卸载组件并再次挂载它。

  2. 更新方法

    • componentWillReceive()
      这个方法在更新阶段被第一个调用,具体来说,就是当组件从它的父组件接收到新属性时被调用。

      此方法让我们可以使用 this.props 对象和 nextProps 对象来比较当前组件和下一个组件的属性。根据比较结果,可以选怎使用 this.setState() 函数来更新组件的 state,在这种场景下将不会触发额外的渲染。

      不管在 componentWillReceive() 方法中调用 this.setState() 多少次,它都不会触发组件额外的渲染。React 做了内部优化,会把状态更新操作放在一起批量执行。

    • shouldComponentUpdate()
      这个方法在更新阶段被第二个调用,通过 shouldComponentUpdate() 方法,我们可以决定组件的下一个状态是否触发组件的重新渲染。这个方法返回一个布尔值,默认为 true。如果为 false,下面的组件方法都不会被调用:

      • componentWillUpdate()
      • render()
      • componentDidUpdate()

      如果跳过对组件的 render() 方法的调用,就会阻止该组件的重新渲染,这将提高应用程序的性能,因为没有额外的 DOM 改变。

    • componentWillUpdate()
      这个方法在 React 即将更新 DOM 之前被调用。它得到以下两个参数:

      • nextProps:下一个属性对象
      • nextState:下一个状态对象

      在调用 componentWillUpdate() 方法之后,React 调用 render() 方法来执行 DOM 更新。然后 componentDidUpdate() 方法被调用。

    • componentDidUpdate()
      这个方法在 React 更新 DOM 之后被 立即 调用。它得到如下两个参数:

      • precProps:上一个属性对象
      • prevState:上一个状态对象

      我们将使用这个方法来操作更新后的 DOM 或者执行渲染后的操作。

  3. 卸载方法

    • 在这个阶段 React 仅提供一个方法,那就是 componentWillUnmount()
      这个方法在 React 即将从 DOM 中删除并销毁组件之前被调用。

      对于清理组件在安装或者更新阶段创建的所有数据,这个方法是很有用的。

      如果你已经在 componentDidMount() 方法中创建了额外的 DOM 元素,那么 componentWillUnmount() 是删除他们最好的地方。

在整合 React 组件和其他 JavaScript API 时,可以将 componentDidMount() 和 componentWillUnmount() 方法想象成一个两步机制:

  1. 在 componentDidMount() 方法中初始化它们。
  2. 在 componentWillUnmount() 方法中结束它们。

设置 React 组件的默认属性

组件可以使用 getDefaultProps() 方法设置一个默认值,如果父组件传递了 this.props.text 属性,那么默认值将会被覆盖。

验证 React 组件的属性

在 React 中,使用组件的 propTypes 对象来验证组件的属性:

propTypes: {
    propertyName: validator
}

在这个对象中,你需要指定一个属性名和一个用来确定属性是否有效的验证器函数,

React 提供了一些预置的验证器供我们使用,他们都定义在 React.PropTypes 对象上,如下:

默认情况下,使用 React.PropTypes 验证器验证的所有属性都是可选的。可以把任何一个属性设置为 isRequiredis ,来确保当没有传递该属性的时候会在 JavaScript 控制台显示一条警告信息:

propTypes: {
    propertyName: React.PropTypes.number.isRequiredis
}

也可以指定自定义验证函数,该函数需要在验证失败的时候返回一个 Error 对象:

propTypes: {
    propertyName: function(properties, propertyName, componentName){
        // ... 验证失败
        return new Error('A property is not valid.');
    }
}

构建复杂的 React 组件

待续...

上一篇下一篇

猜你喜欢

热点阅读