React

来源:互联网 发布:陶瓷泥 知乎 编辑:程序博客网 时间:2024/06/17 13:39

1.Hello world

注意:

1.最后一个

<body>  <div id="example"></div>  <script type="text/babel">    ReactDOM.render(      <h1>Hello, world!</h1>,      document.getElementById('example')    );  </script></body>

ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。

2.JSX 语法规则

HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写

JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析

2.1 操作数组-使用map

<body>  <div id="example"></div>  <script type="text/babel">    var names = ['Alice', 'Emily', 'Kate'];    ReactDOM.render(      <div>      {        {/*names.map(function (name) {          return <div>Hello,{name}!</div>        })*/}          names.map(name=>{return <div>Hello,{name}!</div>})      }      </div>,      document.getElementById('example')    );  </script></body>

2.2 展开数组内容

JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员
arr变量是一个数组,结果 JSX 会把它的所有成员,添加到模板
可以使用{}直接得到数组内的元素

<script type="text/babel">  var arr = [    <h1>Hello world!</h1>,    <h2>React is awesome</h2>,<h5>test add</h5>  ];  ReactDOM.render(    <div>{arr}</div>,    document.getElementById('example')  );</script>

3. 组件

3.1 封装组件 – this.props

React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类

名称必须大写

<body>  <div id="example"></div>  <script type="text/babel">    {/*var HelloMessage = React.createClass({      render: function() {        return <h1>Hello {this.props.name}</h1>;      }    });*/}    var TestMsg = React.createClass({      render : function () {        return <h3>Test,{this.props.xx},{this.props.yy}</h3>      }    });    ReactDOM.render(      {/*<HelloMessage name="John" />,*/}            <TestMsg xx="Bob" yy="Tom"/>,      document.getElementById('example')    );  </script></body>

上面代码中,变量 HelloMessage 就是一个组件类。模板插入 时,会自动生成 HelloMessage 的一个实例(下文的”组件”都指组件类的实例)。所有组件类都必须有自己的 render 方法,用于输出组件。

注意

组件类的第一个字母必须大写,否则会报错,比如HelloMessage不能写成helloMessage。另外,组件类只能包含一个顶层标签,否则也会报错。

var HelloMessage = React.createClass({  render: function() {    return <h1>      Hello {this.props.name}    </h1><p>      some text    </p>;  }});

上面代码会报错,因为HelloMessage组件包含了两个顶层标签:h1和p。
组件的用法与原生的 HTML 标签完全一致,可以任意加入属性,比如 ,就是 HelloMessage 组件加入一个 name 属性,值为 John。组件的属性可以在组件类的 this.props 对象上获取,比如 name 属性就可以通过 this.props.name 读取。

注意:

添加组件属性,有一个地方需要注意,就是 class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。

3.2 this.props.children

this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点

<body>  <div id="example"></div>  <script type="text/babel">    var NotesList = React.createClass({      render: function() {        return (          <ol>            {              React.Children.map(this.props.children, function (child) {                return <li>{child}</li>;              })            }          </ol>        );      }    });    var DiList = React.createClass({        render : function () {            return(              <div>{                React.Children.map(this.props.children,        xyz=>{return <p>{xyz}</p>})              }             </div>            )        }    });    ReactDOM.render(     /* <NotesList>*/      <DiList>        <span>hello</span>        <span>world</span>      </DiList>,      document.getElementById('example')    );  </script></body>

上面代码的 NoteList 组件有两个 span 子节点,它们都可以通过 this.props.children 读取

注意

this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。

React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。更多的 React.Children 的方法,请参考官方文档。

3.3 自定义属性赋值过滤器 – PropTypes

组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。
组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求

<body>  <div id="example"></div>  <script type="text/babel">    var data = 'xxx';    var arr = ['zhangsan', 'lisi'];    var MyTitle = React.createClass({      propTypes: {        title: React.PropTypes.string.isRequired,        xx : React.PropTypes.array.isRequired,      },      render: function() {        return <h1> {this.props.title},{this.props.xx}</h1>;      }    });    ReactDOM.render(      <MyTitle title={data} xx={arr}/>,      document.getElementById('example')    );  </script></body>

上面的Mytitle组件有一个tin tle属性。PropTypes 告诉 React,这个 title 属性是必须的,而且它的值必须是字符串。现在,我们设置 title 属性的值是一个数值。

若将title设置为数字就通不过验证,控制台就会报错

4. 组件的事件处理

4.1 真实的DOM节点—this.refs

组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。
但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性

<body><div id="example"></div><script type="text/babel">    var MyComponent = React.createClass({        handleClick: function () {            this.refs.myTextInput.focus();        },        render: function () {            return (                    <div>                        <input type="text" ref="myTextInput"/>                        <input type="button" value="Focus the text input" onClick={this.handleClick}/>                    </div>            );        }    });    var MyComp = React.createClass({       click : function () {           console.log('点击了');         this.refs.inps.focus();       },        render : function () {            return(<div>                <input type="text" ref="inps"/>                <input type="button" value="click me" onClick={this.click}/>            </div>)        }    });    ReactDOM.render(            {/*<MyComponent />,*/}            <MyComp />,            document.getElementById('example')    );</script></body>

组件 MyComponent 的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。

注意

由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click 事件的回调函数,确保了只有等到真实 DOM 发生 Click 事件之后,才会读取 this.refs.[refName] 属性。
React 组件支持很多事件,除了 Click 事件以外,还有 KeyDown 、Copy、Scroll 等,完整的事件清单请查看官方文档。

4.2 状态机—this.state

组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI

<body><div id="example"></div><script type="text/babel">        var ClickButton = React.createClass({        //在组件挂载之前调用一次。返回值将会作为 this.state 的初始值。        getInitialState : function () {            return {liked : false};        },        setText : function () {            console.log(this.state);            this.setState({liked : !this.state.liked});        },        render : function () {            var text = this.state.liked ? 'dog' : 'cat';            return(                    <h4 onClick={this.setText}>{text}</h4>            )        }    });    ReactDOM.render(            <ClickButton />,            document.getElementById('example')    );</script></body>

上面代码是一个 LikeButton 组件,它的 getInitialState 方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取。当用户点击组件,导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。

4.3 props 和state的区别

由于 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。

4.4 模型数据绑定 – 表单

<div id="example"></div><script type="text/babel">  var Input = React.createClass({    getInitialState: function() {      return {value: 'Hello!'};    },    //传入e / event     //类似ng使用e.target.value得到当前世界的value值    setChange: function(e) {      console.log(this.state,"setChange");      this.setState({value: e.target.value});    },    render: function () {      console.log(this.state,"render");      var value = this.state.value;      return (        <div>          <input type="text" value={value} onChange={this.setChange} />          <p>{value}</p>        </div>      );    }  });  ReactDOM.render(<Input/>, document.getElementById('example'));</script>

上面代码中,文本输入框的值,不能用 this.props.value 读取,而要定义一个 onChange 事件的回调函数,通过 event.target.value 读取用户输入的值。textarea 元素、select元素、radio元素都属于这种情况,更多介绍请参考官方文档。

5. 组件的生命周期

componentWillMount在页面被渲染之前执行,也就是在render方法之前执行,我一般在componentWillMount中触发 请求数据的方法。

componentDidMount类似js中的window.onload,执行在render方法之后,也就是页面的组件渲染完毕之后

5.1 三种状态

组件的生命周期分为三种状态Mounting:已插入真实 DOMUpdating:正在被重新渲染Unmounting:已移出真实 DOM

5.2 五种处理函数

React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数

PS : 移出真实DOM没有componentDidUnmount( )

理解方式:  do的形态do will 代表进去状态之前,将来时。did代表进入状态之后,过去时componentWillMount()componentDidMount() – 类似window.onload。在render方法后componentWillUpdate(object nextProps, object nextState)componentDidUpdate(object prevProps, object prevState)componentWillUnmount()

5.3 两种特殊状态处理函数

componentWillReceiveProps(object nextProps):
已加载组件收到新的参数时调用

shouldComponentUpdate(object nextProps, object nextState):
组件判断是否重新渲染时调用

<body>  <div id="example"></div>  <script type="text/babel">    var Hello = React.createClass({      getInitialState: function () {        return {opacity: 1.0};      },      componentDidMount: function () {        this.timer = setInterval(function () {          var opacity = this.state.opacity;          opacity -= .05;          if (opacity < 0.1) {            opacity = 1.0;          }          this.setState({            opacity: opacity          });        }.bind(this), 100);      },      render: function () {        return (          <div style={{opacity: this.state.opacity}}>            Hello {this.props.name}          </div>        );      }    });    ReactDOM.render(      <Hello name="world"/>,      document.getElementById('example')    );  </script></body>

上面代码在hello组件加载以后,通过 componentDidMount 方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。

另外,组件的style属性的设置方式也值得注意,

不能写成style="opacity:{this.state.opacity};"而要写成style={{opacity: this.state.opacity}}

这是因为 React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。

6. Ajax

组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI

<body>  <div id="example"></div>  <script type="text/babel">  var UserGist = React.createClass({    getInitialState: function() {      return {        username: '',        lastGistUrl: ''      };    },   componentDidMount: function() {     $.get(this.props.source, function(result) {       var lastGist = result[0];       if (this.isMounted()) {         this.setState({           username: lastGist.owner.login,           lastGistUrl: lastGist.html_url         });       }     }.bind(this));    },  render: function() {    return (      <div>        {this.state.username}'s last gist is <a href={this.state.lastGistUrl}>here</a>.      </div>    );  }});ReactDOM.render(  <UserGist source="https://api.github.com/users/octocat/gists" />,  document.getElementById('example'));    </script>  </body>

上面代码使用 jQuery 完成 Ajax 请求,这是为了便于说明。React 本身没有任何依赖,完全可以不用jQuery,而使用其他库。

<body>    <div id="example"></div>    <script type="text/babel">var RepoList = React.createClass({  getInitialState: function() {    return {      loading: true,      error: null,      data: null    };  },  componentDidMount() {    this.props.promise.then(      value => this.setState({loading: false, data: value}),      error => this.setState({loading: false, error: error}));  },  render: function() {    if (this.state.loading) {      return <span>Loading...</span>;    }    else if (this.state.error !== null) {      return <span>Error: {this.state.error.message}</span>;    }    else {      var repos = this.state.data.items;      var repoList = repos.map(function (repo, index) {        debugger;        return (          <li key={index}><a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br/> {repo.description}</li>        );      });      return (        <main>          <h1>Most Popular JavaScript Projects in Github</h1>          <ol>{repoList}</ol>        </main>      );    }  }});ReactDOM.render(  <RepoList promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')} />,  document.getElementById('example'));    </script>  </body>

我们甚至可以把一个Promise对象传入组件
是上面代码从Github的API抓取数据,然后将Promise对象作为属性,传给RepoList组件。
如果Promise对象正在抓取数据(pending状态),组件显示”正在加载”;如果Promise对象报错(rejected状态),组件显示报错信息;如果Promise对象抓取数据成功(fulfilled状态),组件显示获取的数据。

原创粉丝点击