React学习笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010412719/article/details/78384846

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

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页