1. react安装 #

create-react-app是你开始构建一个全新单页应用的最好方式

npm install -g create-react-app
create-react-app my-app

cd my-app
npm start

2. React初体验 #

ReactDOM.render(
    <h1>珠峰培训</h1>,
        document.getElementById('app')
    );

3. JSX #

JSX是一种JS和HTML混合的语法,将组件的结构、数据甚至样式都聚合在一起定义组件,会编译成普通的Javascript。

var persons = ['阿米尔汗', '范冰冰', '郭跃'];
var style = {color:'red'};
ReactDOM.render(
  <div>
  {
    persons.map(function (person) {
      return <div style={style}>Hello, {person}!</div>
    })
  }
  </div>,
  document.getElementById('app')
);

4. 组件 #

我们可以很直观的将一个复杂的页面分割成若干个独立组件,每个组件包含自己的逻辑和样式 再将这些独立组件组合完成一个复杂的页面。 这样既减少了逻辑复杂度,又实现了代码的重用

React允许将代码封装成组件,然后像插入普通HTML标签一样,在网页中插入这个组件

组件类的第一个字母必须大写 组件类能且只能包含一个顶层标签

import React from 'react';
class Message extends React.Component{
    render: function() {
        return <h1>Hello</h1>;
    }
});
ReactDOM.render(
    <Message/>,
    document.getElementById('app')
);

5. 属性 #

每个组件可以有自己的属性,一般用来存放组件初始后不变的数据,比如人的性别,姓名等 属性一般用作组件的数据源,一般由父组件传入,比如你的名字一般是由你父母取的 属性可以通过this.props中取出

Person.propTypes = { name: PropTypes.string.isRequired }; Person.defaultProps = { name: '无名' }; let props = {name:'张三'}; ReactDOM.render( ,//属性可以在使用组件时传入 document.getElementById('app') );

## 6. this.props.children
this.props对象的属性与组件实例的属性一一对应,但this.props.children属性表示组件的所有子节点 React.Children.map是一个工具方法,用于实现对数组元素的映射
```javascript
class Message extends React.Component{
    render: function() {
      return (
            <ol>
                {
                    React.Children.map(this.props.children,
                      function (child) {
                        return <li>{child}</li>;
                    })
                }
            </ol>
      );
    }
});

ReactDOM.render(
    <Person>
        <span>大毛</span>
        <span>二毛</span>
        <span>三毛</span>
    </Person>,
    document.getElementById('app')
);

7. 状态和事件处理 #

8. 表单元素双向数据绑定 #

class Input extends React.Component{
     constructor(props){
          super(props);
          this.state = {value: '珠峰培训'};
        }
    handleChange: function(event) { //处理改变事件
        this.setState({value: event.target.value});
    },
    render: function () {
        var value = this.state.value;
        return (
            <div>
                <input style={{color:'red'}} type="text"
                value={value} onChange={this.handleChange} />
                <p>{value}</p>
            </div>
        );
    }
});

ReactDOM.render(<Input/>, document.getElementById('app'));

注意: 如果给表单元素设置了value属性,则必须指定onChange事件处理函数,否则 此字段会变成只读状态

9. 复合组件 #

多个简单的组件嵌套,可构成一个复杂的复合组件,从而完成复杂的交互逻辑

class Panel extends React.Component{
    render: function () {
        return (
            <div className="panel panel-default">
                <PanelHead head={this.props.head}/>
                <PanelBody body={this.props.body}/>
            </div>
        );
    }
});


class PanelHead extends React.Component{
    render: function () {
        return (
            <div className="panel-heading">
                {this.props.head}
            </div>
        );
    }
});


class PanelBody extends React.Component{
    render: function () {
        return (
            <div className="panel-body">
                {this.props.body}
            </div>
        );
    }
});

ReactDOM.render(
    <Panel
        head="头部"
        body="正文"
    />,
    document.getElementById('app')
);

10. 组件的生命周期 #

React中可以指定在组件的生命周期的不同阶段执行的函数

渲染前 getDefaultProps 在组件类创建的时候调用一次,则此处返回的对象中的相应属性将会合并到this.props getInitialState 在组件挂载之前调用一次。返回值将会作为this.state的初始值。 componentWillMount 在首次渲染之前触发 渲染 render 当调用的时候,会检测this.props和this.state,返回一个组件 渲染后 componentDidMount 在初始化渲染执行之后立刻调用一次 shouldComponentUpdate 在接收到新的props或者state,将要渲染之前调用,返回false则不更新组件 componentWillUpdate 做一些更新之前的准备工作 componentDidUpdate 更新之后触发 componentWillReceiveProps 在组件接收到新的props的时候调用 移除 componentWillUnmount 在组件从DOM中移除的时候立刻被调用 componentDidUnmount 组件移除之后调用

import React from 'react';
import ReactDOM from 'react-dom'
/**
 * 1.实例化组件类,并调用它的render方法得到虚拟DOM元素
 * 2.React将要把此虚拟DOM元素挂载到页面中
 */
export default class Counter extends React.Component {
    constructor(props){
        super(props);
        this.state = {number:0};
    }
    componentWillMount(){
        console.log('1. componentWillMount 组件将要被挂载')
    }
    componentDidMount(){
        console.log('3. componentDidMount 组件挂载结束')
    }
    handleClick=() =>{
        this.setState({number:this.state.number+1});
    }
    //组件是否应该更新
    shouldComponentUpdate(newProps,newState){
        console.log('4. shouldComponentUpdate 组件是否要被更新')
       if(newState.number%2==0){
           return true;
       }else{
           return false;//如果返回false render方法将不再执行
       }
    }
    componentWillUpdate(){
        console.log('5. componentWillUpdate 组件将要更新')
    }
    componentDidUpdate(){
        console.log('6. componentWillUpdate 组件更新完成')
    }
    componentWillUnMount(){
        console.log('7. componentWillUnMount 组件将要被卸载')
    }
    render() {
        console.log('2. render 渲染')
        return (
            <div>
                <button onClick={this.handleClick} className="btn btn-primary">
           父计数器 <span className="badge">{this.state.number}</span>
                </button>
            </div>
        )
    }
}

11. DOM操作 #

给组件加上ref="xxx"后,可在父组件中通过this.refs.xxx获取该DOM元素

import React from 'react';
//每个表单元素的值是受组件状态的控制
// 10 8 16
// 10
export default class Calculator extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            numA:0,
            op:'+',
            numB:0
        }
    }
    changeA(event){
        this.setState({
            numA:event.target.value
        });
    }
    changeOp(event){
        this.setState({
            op:event.target.value
        });
    }
    changeB(event){
        this.setState({
            numB:event.target.value
        });
        console.log(this.state.numA+this.state.op+this.state.numB);
    }
//warning.js:36Warning: Failed form propType: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field.
    render(){
        return (
            <div>
                <input onChange={this.changeA.bind(this)} type="text" value={this.state.numA}/>
                <input onChange={this.changeOp.bind(this)}  type="text" value={this.state.op}/>
                <input onChange={this.changeB.bind(this)}  type="text" value={this.state.numB}/>
                <span>{eval(this.state.numA+this.state.op+this.state.numB)}</span>
            </div>
        )
    }
}

12. 百度搜索框 #

import React from 'react';
import $ from 'jquery';
/**
 * 1. 为输入框绑定 onchange事件,当有新的值的时候会执行方法
 * 2. 获得输入框的值,然后调用百度的接口获取联想数组
 * 3. 把数组赋给状态对象的words属性
 */
export default class Suggest extends React.Component {
    constructor(props) {
        super(props);
        this.state = {wd:'',words: [],pos:-1};
    }

    handleChange = (event) => {
        let wd = event.target.value;
        this.wd = wd;
        this.setState({wd});
        // 1.success
        $.ajax({
            type: 'GET',//请求的方法为GET
            url: `http://www.baidu.com/su`,
            data: {wd},//此对象会转成查询字符串放在url后面
            jsonp: 'cb',//指定参数名 cb=方法名
            dataType: 'jsonp',//指定返回值的类型
            success: (result) => {
                this.setState({
                    words: result.s
                });
            }
        });

    }
    handleKeyDown = (event)=>{
        let code = event.keyCode;
        if(code == 38 || code == 40){
            let pos = this.state.pos;
            if(code == 38){//向上
                pos--;
                if(pos == -2){
                    pos = this.state.words.length -1;
                }
            }else if(code == 40){//向下
                pos++;
                if(pos == this.state.words.length){
                    pos = -1;
                }
            }
            this.setState({pos,wd:this.state.words[pos]});
        }
    }
    render() {
        return (
            <div style={{marginTop: 30}} className="container">
                <div className="row">
                    <div className="col-md-6 col-md-offset-3">
                        <input type="text" className="form-control" value={this.state.pos ==-1?this.wd:this.state.wd} onKeyDown={this.handleKeyDown} onChange={this.handleChange}/>
                    </div>
                </div>
                <div className="row">
                    <div className="col-md-6 col-md-offset-3">
                        <ul className="list-group">
                            {
                                this.state.words.map((word, index) => (
                                    <li className={"list-group-item "+(this.state.pos==index?'active':'')} key={index}>{word}</li>
                                ))
                            }
                        </ul>
                    </div>
                </div>
            </div>
        )
    }
}

13. 珠峰留言板 #

var Board = React.createClass({
    getInitialState: function () {
        return {
            msg: '请输入',
            messages:this.props.messages
        };
    },
    render: function () {
        return (
            <div>
                <h1>{this.props.title}</h1>
                <input type="text" defaultValue={this.state.msg}
                ref="txtMsg" onClick={this.clear}/>
                <input type="button" value='发言' onClick={this.leaveMsg}/>
                <ul>
                    {
                        this.state.messages.map(function (item, index) {
                            return <li key={index}>{item}</li>
                        })
                    }
                </ul>
            </div>
        )
    },
    clear:function(){
        this.refs.txtMsg.value =  '';
    },
    leaveMsg: function (event) {
     this.state.messages.push(this.refs.txtMsg.value);
       //每次状态都是一个新的state对象
     localStorage.setItem('messages',JSON.stringify(this.state.messages));
     this.setState({
           messages:this.state.messages
     },function(){
           this.refs.txtMsg.value =  '';
     });
    }
})
var data = {
    title: '珠峰留言版',
    messages: JSON.parse(localStorage.getItem('messages'))||[]
}

ReactDOM.render(
    <Board {...data}/>,
    document.getElementById('app')
);