React学习笔记

来源:互联网 发布:java时区转换 编辑:程序博客网 时间:2024/06/16 14:38

React学习笔记

跟着参考资料一路实践了下,终于算是对React有一定的了解了,这篇博文就是相关的一些记录。

1、使用create-react-app快速构建React开发环境

create-react-app是来自于Facebook,通过该命令我们无需配置就能快速构建React开发环境。

create-react-app自动创建的项目是基于Webpack+ES6.

首先切换到相应的目录,然后在命令行执行以下命令创建项目:

    $ npm install -g create-react-app    $ create-react-app my-app    $ cd my-app/    $ npm start

简单的例子

    <!DOCTYPE html>    <html>      <head>        <meta charset="UTF-8" />        <title> React 实例</title>        <script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script>        <script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script>        <script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script>      </head>      <body>        <div id="example"></div>        <script type="text/babel">          ReactDOM.render(            <div>            <h1>heihei</h1>            <h2>欢迎学习 React</h2>            </div>            ,            document.getElementById('example')          );        </script>      </body>    </html>

以上的代码有两点需要注意:

1)最后一个<script>标签的 type 属性为 text/babel 。这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel"

2)ReactDOM.render方法是将模版转换为html并插入到指定的节点中。例子中就是插入到id=“example” 的dom节点中。

注意:以上代码中ReactDOM.render的第一个参数中嵌套多个 HTML 标签,需要使用一个 div 元素包裹它,否则报错。

即如下的代码是不正确的:

    ReactDOM.render(      <h1>这是错误的例子</h1>      <span>假设这里是标题下面的内容</span>,      document.getElementById("example")    );  

JavaScript 表达式

我们可以在 JSX 中使用 JavaScript 表达式。表达式写在花括号 {} 中。

实例如下:

    ReactDOM.render(        <div>          <h1>{1+1}</h1>        </div>        ,        document.getElementById('example')    );  

在 JSX 中不能使用 if else 语句,但可以使用 conditional (三元运算) 表达式来替代。以下实例中如果变量 i 等于 1 浏览器将输出 true, 如果修改 i 的值,则会输出 false.

    ReactDOM.render(        <div>          <h1>{i == 1 ? 'True!' : 'False'}</h1>        </div>        ,        document.getElementById('example')    );

注释

1、在标签内部的注释写在花括号{}中

2、在标签外部的注释不需要使用花括号{}.

ReactDOM.render(    /*注释 */    //注释    <h1>wojiushimogui {/*注释*/}</h1>,    document.getElementById('example'));

HTML 标签 vs. React 组件

React 可以渲染 HTML 标签 (strings) 或 React 组件 (classes)。

要渲染 HTML 标签,只需在 JSX 里使用小写字母的标签名。

var myDivElement = <div className="foo" />;ReactDOM.render(myDivElement, document.getElementById('example'));

要渲染 React 组件,只需创建一个大写字母开头的本地变量。

var MyComponent = React.createClass({/*...*/});var myElement = <MyComponent someProperty={true} />;ReactDOM.render(myElement, document.getElementById('example'));

React 的 JSX 使用大、小写的约定来区分本地组件的类和 HTML 标签。

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

注意:

由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代,React DOM 使用 className 和 htmlFor 来做对应的属性。

state

先看一个例子,这里和前面的例子不同,这里将组件单独写在一个文件中了。定义组件的方式有很多中,通过React.createClass()是一种方式,下面通过extends Component是另外一种方式,如果想了解更多,可以参考这篇博文.

    import React,{Component} from 'react';    class LikeButton extends Component {        constructor(props) {            super(props);            this.state = {                like: false,            };        }        clickHandler() {            this.setState({like: !this.state.like});        }        render() {            var like = this.state.like ? '喜欢':'不喜欢';            return (<div>                <button onClick={this.clickHandler.bind(this)}>你{like}我</button>            </div>);        }    }    export default LikeButton;

该组件的state中有一个like字段,初始化为false,当我们点击button按钮时,会调用clickHandler方法来对state进行改变,当state改变之后,然后根据新的 state 重新渲染界面。

值得注意的是:一定要这样写onClick={this.clickHandler.bind(this)},如果写成onClick={this.clickHandler}会报:TypeError: Cannot read property ‘setState’ of undefined错误。

还有一点需要注意:onClick 等事件,与原生 HTML 不同,on 之后第一个字母是大写的!
比如本章实例中,如果将 onClick={this.clickHandler.bind(this)} 换成 onclick={this.clickHandler.bind(this)} 则点击事件不再生效。

其中,clickHandler方法也可以这么写,两者的效果一样。

    clickHandler() {        this.setState(function (state) {            return {like:!state.like}        })    }

在容器中这样调用就可以了

    ReactDOM.render(<div>                                               <LikeButton/>                    </div>,          document.getElementById('root'));

state和props的区别

上一节通过一个例子介绍了state如何来使用,这一节来介绍state和props的区别。

state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 props相当于组件的数据流,它总是会从父组件向下传递至所有的子组件中。

看如下的例子,就是state和props结合使用的一个实例

    ReactDOM.render(<div>                                       <Website name="wojiushimogui" link="www.baidu.com"/>                                            </div>, document.getElementById('root'));

组件Website定义如下:

    import React,{Component} from 'react';    import Name from './Name';    import Link from './Link';    class Website extends Component {        constructor(props){            super(props);            this.state={                name:this.props.name,                link:this.props.link            };        }        changeNameAndLink() {            this.setState({name:this.state.name+'1',link:this.state.link+'2'});        }        render() {            return (                <div>                    <button onClick={this.changeNameAndLink.bind(this)}>点我改变name 和 link</button>                    <Name name={this.state.name}/>                    <Link link={this.state.link}/>                </div>            );        }    }    export default Website; 

组件Website首先在构造函数中利用props中的属性来初始化state中的属性,然后将state中的属性值传给子组件Name和Link。

子组件Name和Link的定义如下:Name组件和Link组件将props中相应的属性值显示出来。

    //Name.js    import React,{Component} from 'react';    class Name extends Component {        render() {            return (<p>{this.props.name}</p>);        }    }    export default Name;    //Link.js    import React,{Component} from 'react';    class Link extends Component {        render() {            return <a href={this.props.link}>{this.props.link}</a>;        }    }    export default Link;

PropTypes

Props 验证使用 propTypes,它可以保证我们的应用组件被正确使用,PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。

在现在很多参考资料中,都是使用React.PropTypes下提供的验证器来验证传入的数据是否有效,写法如下:

PropsTypeExamp.propTypes = {    //title: PropTypes.string.isRequired,    title:React.PropTypes.string.isRequired,};

如果你使用的react的版本在15.5.0以上,则如果使用如上的语句,则会报如下的错误:React.PropTypes is deprecated since React 15.5.0, use the npm module prop-types instead 。

错误提示的意思告诉了我们要干什么,修正该错误的方法为:

1、安装prop-types这个包

2、具体写法如下:

    import React,{Component} from 'react';    import PropTypes from 'prop-types'    class PropsTypeExamp extends Component {        render() {              return (                <div>                    <p>{this.props.title}</p>                </div>            );        }    }    PropsTypeExamp.propTypes = {        title: PropTypes.string.isRequired,    };  

关于PropTypes,更多可以看这里。

组件的生命周期

借用慕课网上关于React课上的一张图,很好的描述了组件的生命周期。

下面看一个componentDidMount的例子

即在挂载之后定时的变化opacity,然后会触发重新渲染。

    import React,{Component} from 'react';    class OpacityExample extends Component {        constructor(props){            super(props);            this.state={                opacity: 1,            };        }        componentDidMount() {            this.timer = setInterval(function () {                var opacity = this.state.opacity;                opacity -=0.1;                if(opacity<=0.1){                    opacity = 1;                }                this.setState({opacity:opacity});            }.bind(this),100);        }        render() {            return (                <div style={{opacity : this.state.opacity}}>                    hello,{this.state.opacity}                </div>            );        }    }    export default OpacityExample;  

再看一个例子来理解Component的生命周期。

    import React,{Component} from 'react';    class Name extends Component {        componentWillMount() {            alert("component will mount!");        }        componentDidMount() {            alert("component did mount!");        }        componentWillReceiveProps(newProps){            alert("component will receiver props");        }        /*        * //明确的要返回true,则后面才依次执行 componentWillUpdate  render componentDidUpdate,三个方法,        * 如果返回的是false或者是省略return语句,则后面的三个方法都不能被执行。         }        * */        shouldComponentUpdate(newProps, newState) {            alert("should component update!");            return true;        }        componentWillUpdate(nextProps, nextState) {            alert("component will update");        }        componentDidUpdate(prevProps, prevState) {            alert("component did update");        }        render() {            alert("component render")            return (<p>{this.props.name}</p>);        }    }    export default Name;

Name组件在Website组件的子组件,如下:

    class Website extends Component {        constructor(props){            super(props);            this.state={                name:this.props.name,                link:this.props.link            };        }        changeNameAndLink() {            this.setState({name:this.state.name+'1',link:this.state.link+'2'});        }        render() {            return (                <div>                    <button onClick={this.changeNameAndLink.bind(this)}>点我改变name 和 link</button>                    <Name name={this.state.name}/>                    <Link link={this.state.link}/>                </div>            );        }    }

Website被如下的方式调用即可:

    ReactDOM.render(<div>                                               <Website name="wojiushimogui" link="www.baidu.com"/>                    </div>, document.getElementById('root'));   

在第一次渲染的时候:会依次调用Name中的componentWillMount、 render、componentDidMount 这三个方法。当我们点击Website中的按钮而改变state的值后会触发更新,则会依次调用Name中的componentWillReceiveProps、 shouldComponentUpdate、 componentWillUpdate、 render、 componentDidUpdate 方法。

在实践过程中,有一点需要注意:shouldComponentUpdate方法如果返回的ture,则执行后面的方法,如果返回的false或者省略return语句则不执行后面的几个方法,这与生命周期图上表述的一致。

React ajax请求

通过AJAX加载数据是一个很普遍的场景。在React组件中如何通过AJAX请求来加载数据呢?首先,AJAX请求的源URL应该通过props传入;其次,最好在componentDidMount函数中加载数据。加载成功,将数据存储在state中后,通过调用setState来触发渲染更新界面。

例子

    import React,{Component} from 'react';    import $ from 'jquery'    class UserGist extends Component {        constructor(props) {            super(props);            this.state={                username:'',                lastGistUrl:'',            };        }        componentDidMount() {            this.serverRequest = $.get(this.props.source,function (result) {                var lastGist = result[0];                this.setState({username:lastGist.owner.login,lastGistUrl:lastGist.html_url})            }.bind(this));        }        render() {            return (                <div>                    <p>username:{this.state.username}</p>                    <a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a>                </div>            );        }    }    export default UserGist;

会遇到如下的错误:Module not found: Can’t resolve ‘jquery’

解决方法:在package.json添加库依赖:"jquery": "^3.2.1",然后在使用的Component中import $ from 'jquery'即可。

具体的调用如下:

    ReactDOM.render(<div>                           <UserGist source="https://api.github.com/users/octocat/gists"/>                    </div>, document.getElementById('root'));

表单与事件

假设有这样一个需求:有个输入框、一个显示框,实时的将输入框中的内容显示在显示框中,即将用户在输入框中输入的内容实时的显示在显示框中。

这里写了一个组件,代码如下:

    import React,{Component} from 'react';    class InputAndDisplay extends Component {        constructor(props) {            super(props);            this.state={                content:'',            };        }        changeHandler(event) {            this.setState({content:event.target.value});        }        render(){            return (                <div>                    <input type="text" value={this.state.content} onChange={this.changeHandler.bind(this)}/>                    <p>{this.state.content}</p>                </div>            );        }    }    export default InputAndDisplay;

在前不久,遇到过这样一个问题:需要在子组件中调用父组件的方法来改变父组件的state,应该如何来做呢?

解决方法:需要在父组件通过创建事件句柄 (handleChange) ,并作为 props 传递到你的子组件上。

还是以上面的例子为例来做。

    import React,{Component} from 'react';    import Content from './Content'    class ContentContainer extends Component {        constructor(props) {            super(props);            this.state={                value :'username',            };        }        changeHandler(event) {            this.setState({value:event.target.value});        }        render() {            return (                <div>                    <Content value={this.state.value} changeHandler={this.changeHandler.bind(this)}/>                </div>            );        }    }    export default ContentContainer;

自组件Content.js的内容如下:

    import React,{Component} from 'react';    class Content extends Component {        render() {            return (                <div>                    <input type="text" value={this.props.value} onChange={this.props.changeHandler}/>                    <p>用户输入的内容为:{this.props.value}</p>                </div>            );        }    }    export default Content;

这样,在自组件的onChange 方法将触发 state 的更新并将更新的值传递到子组件的输入框的 value 上来重新渲染界面。

总之:当你需要从子组件中更新父组件的 state 时,你需要在父组件通过创建事件句柄 (handleChange) ,并作为 prop (updateStateProp) 传递到你的子组件上.

React refs

获取真实的Dom节点。

    import React,{Component} from 'react';    class GetDomNode extends Component {        clickHandler() {            this.refs.textInput.focus();        }        render() {            return (                <div>                    <button  onClick={this.clickHandler.bind(this)}>focus the input text</button>                    <input type="text" ref="textInput"/>                </div>            );        }    }    export default GetDomNode;

参考资料

1、 http://www.runoob.com/react/react-refs.html

2、 http://www.ruanyifeng.com/blog/2015/03/react.html

原创粉丝点击