react基础

来源:互联网 发布:网络课程培训心得 编辑:程序博客网 时间:2024/06/06 11:48

简介
在目前看来react毫无疑问是最流行的框架,没有之一。
之前看了阮一峰写的react基础,写的非常好。但这个教程在现在看来,有些用法已经过时了。
所以我打算用ES6语法写一篇这样的文章。
说到ES6,大家都知道目前还不能兼容所有浏览器,因此我们要用到babel。把ES6代码转化为浏览器识别的ES5代码。
在这里我用webpack搭建的环境,没用过webpack的,可以看我之前写的文章。这里就不一一讲解。


一、HTML模板


<!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />    <title>react主页</title></head><body>    <div id="root"></div>    <script src="http://localhost:8080/bundle.js"></script></body></html>

这里的root是根节点,下文就会用到
二.render


render是react的最基本语法,用于将HTML转化为语言,并插入指定的节点。
用react时我们要引进两个库
react和react-dom,用ES6中的import引进,后面每次都需要引入,不然无法执行代码。

import React,{ component } from 'react';import { render } from 'react-dom';
render(    <h1>hello world!</h1>,    document.getElementById('root'))

运行结果如下:

hello world!

三、JSX语法


上一节的代码,HTML语言直接写在javascript语言中,不加任何引号,这就是JSX语法。
它允许HTML和JSX混写。

render(    <div>        {            names.map(function(item,index){                return <h1 key={index}>hello {item}</h1>            })        }    </div>,    document.getElementById('root'))

上面的代码体现了JSX的基本语法规则:遇到HTML(以<开头),就用HTML解析规则;遇到代码块(以{开头),就用javascript规则解析。
上面的代码运行结果如下:
hello 张三
hello 李四
hello 王五

JSX允许在模板中插入javascript变量,如果这个这个变量是一个数组,会展开数组所有的成员。

var arr = [    <h1>hello 张三</h1>,    <h1>hello 李四</h1>];render(    <div>{arr}</div>,    document.getElementById('root'))

执行结果如下:

hello 张三
hello 李四
四、组件


React允许将代码封装成组件(component),然后像插入普通HTML一样,在网页中插入组件。用class定义一个类组件。

class Hello extends Component{    render(){        return (            <h1>hello {this.props.name}</h1>        )    }}render(    <Hello name="张三" />,    document.getElementById('root'))

上面代码,Hello 就是用ES6的class定义的一个类。模板插入时,就会自动生成Hello的一个实例(下文的“组件”都指组件类的实例)。所有的组件类都有自己的render方法,用于输出组件。
PS:

1.组件类的第一个字母必须大写,否则无法显示内容。比如,Hello不能写成hello。2.组件类只能包含一个顶层标签,否则会报错。
class Hello extends Component{    render(){        return (            <h1>hello { this.props.name }</h1>            <h1>小</h1>        )    }}render(    <Hello name="张三" />,    document.getElementById('root'))

上面这个会报错。
但这样不会报错,原因正在探索中

class Hello extends Component{    render(){        return (            <h1>hello { this.props.name}</h1>,            <h1>小</h1>        )    }}render(    <Hello name="张三" />,    document.getElementById('root'))

运行的结果为

父组件<Hello name="张三" />中的name属性传递给子组件。this.props.name用于获取父组件传递的值。
组件的用法和原生的HTML标签完全一样,可以加入任意属性。比如,<Hello name="张三" /> 就是Hello组件加入的一个name属性,值为张三。组件的属性可以在组件的this.props对象上获取。比如那么属性就可以通过this.props.name属性读取。
添加组件属性,需要注意的地方是class属性要写成classNamefor属性要写成htmlFor。这是因为class和for是javascript的保留字。
五、this.props.children
this.props对象的属性与组件的属性一一对应,但是有一个例外就是this.props.children属性,它表示组件的所有子节点。

class NoteList extends Component{    render(){        console.log(this.props.children);        return(            <div>                {                    React.Children.map(this.props.children,function(item,index){                        return <h1 key={index}>{item}</h1>                    })                    // this.props.children.map(function(item,index){                    //  return <h1 key={index}>{item}</h1>                    // })                }            </div>        )    }}render(    <NoteList>        <span>hello</span>        <span>world</span>    </NoteList>,    document.getElementById('root'))

上面代码的NoteList 组件有两个span子节点,它们都可以通过this.props.children读取,运行结果如下:
hello
world
这里要注意的是,this.props.chidren的值有3种可能
第一种可能是:没有子节点,这时它的值为undefined
第二种可能是:只有一个子节点,这时它的值是一个对象。
第三种可能是: 有两个及以上子节点时,它的值是一个数组。
如果用下面这种方法遍历时需要注意:

this.props.children.map(function(item,index){    return <h1 key={index}>{item}</h1>})遍历的是数组还是对象。于是react提供了一种方法,React.Children.map,不管你是数组还是对象我都可以遍历。

六、propTypes


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

class Hello extends Component{    constructor(props){        super(props);    }    render(){        return <h1>{this.props.title}</h1>    }}Hello.propTypes = {    title: React.PropTypes.string}

上面的Hello组件有一个title属性。PropTypes告诉React,这个title属性时必须的,而且它的值必须是字符串,我们给它设置一个数字,看会有什么结果?

var data = 123;render(    <Hello title={data} />,    document.getElementById('root'))

结果呢?报错了

Warning: Failed prop type: Invalid prop `title` of type `number` supplied to `Hello`, expected `string`.    in Hello

如果写成这样,title属性就不会通过验证了,控制台会会报错。

var data = '123';

此外,defaultProps可以设置组件属性的默认值。

class Hello extends Component{    constructor(props){        super(props);    }    render(){        return <h1>{this.props.title}</h1>    }}Hello.defaultProps = {    title: 'hello world'}render(    <Hello />,    document.getElementById('root'))

上面的代码会输出

hello world

七、获取真实的DOM节点


class Hello extends Component{    handleClick(){        this.refs.myTextInput.focus();        console.log(this.refs.myTextInput.focus());    }    render(){        return (            <div>                <input type="text" ref="myTextInput" />                <input type="button" value="Focus the text Input" onClick={this.handleClick.bind(this)} />            </div>        )    }}render(    <Hello />,    document.getElementById('root'))

八、this.state


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

class Hello extends Component{    constructor(props){        super(props);        this.state = {            liked: false        }    }    handleClick(){        this.setState({liked:!this.state.liked})    }    render(){        var text = this.state.liked ? '喜欢':'不喜欢';         return(            <p onClick={this.handleClick.bind(this)}>                You {text} toggle            </p>        )    }}render(    <Hello />,    document.getElementById('root'))

我们逐个代码块分析

constructor(props){    super(props);    this.state = {        liked: false    }}

this.state 初始化状态,所以第一次渲染完之后就是不喜欢

handleClick(){this.setState({liked:!this.state.liked})}

当我们发生点击事件时,就会取它相反的状态。每次修改状态之后就会调用render方法,就会再次渲染页面。
由于this.props和this.state都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是:this.props表示哪些一旦定义就不在改变的特性,而this.state是随着用户互动而产生变化的特性。

九、表单


用户在表单填入的内容属于用户和组件的互动,所以不能用this.props.

class Hello extends Component{    constructor(props){        super(props);        this.state = {            value: 'Hello!'        }    }    handleClick(){        this.setState({liked:!this.state.liked})    }    handleChange(e){        this.setState({value: e.target.value})    }    render(){        var value = this.state.value;        return(            <div>                <input type="text" value={value} onChange={this.handleChange.bind(this)} />                <p>{value}</p>            </div>        )    }}render(    <Hello />,    document.getElementById('root'))

上面的代码中,文本框中的值不能通过this.props.value读取,要定义onChange的回调函数。通e.target.value读取用户输入的值。textarea元素、select元素、radio元素都属于这种情况。
十、组件的生命周期


组件的生命周期分为3个状态:

Mounting: 已插入真实的DOMUpdating:正在被重新渲染UnMounting: 已移除真实的DOM

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

ComponentWillMount()
ComponentDidMount()
componentWillUpdate(object nextProps,object nextState)
componentDidUpdate(object prevProps,object prevState)
componentWillUnMount()

此外,React还提供两种特殊状态的处理函数。

componentWillReceivesProps(object nextProps)已加载组件收到新的参数时调用。
shouldComponentUpdate(object nextProps,object nextState)组件判断是否重新渲染时调用
class Hello extends Component{    constructor(props){        super(props);        this.state = {            opacity: 1.0        }    }    componentDidMount(){        var opacity = this.state.opacity;        this.timer = setInterval(function(){            opacity -= 0.05;            if(opacity < 0.1){                opacity = 1;            }            this.setState({opacity: opacity})        }.bind(this),100)    }    render(){        return (            <h1 style={{opacity:this.state.opacity}}>Hello {this.props.name}</h1>        )    }}render(    <Hello name="xiao" />,    document.getElementById('root'))

十一、 Ajax
组件的数据来源是通过ajax请求从服务器获取,可以使用componentDidMount()方法设置ajax请求,等请求成功之后,再用this.setState方法重新渲染UI。

class Hello extends Component{    constructor(props){        super(props);        this.state = {            username: '',            lastGistUrl: ''        }    }    componentDidMount() {        $.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(){        return(            <div>                {this.state.username}                <a href={this.state.lastGistUrl}>here</a>            </div>        )    }}render(    <Hello source="https://api.github.com/users/octocat/gists" />,    document.getElementById('root'))
原创粉丝点击