react项目基础

一 react简介

1 react 简介

React 是一个用于构建用户界面的 JAVASCRIPT 库。
React 主要用于构建UI,不少人认为 React 是 MVC 中的 V。
React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。
React 拥有较高的性能,代码逻辑很是简单,愈来愈多的人已开始关注和使用它。javascript


React 是解决前端MVC框架中的view视图层的问题
M 是指数据模型,V是指显示的问题,C是指控制的问题 css

2 React 特色

1.声明式设计 −React采用声明范式,能够轻松描述应用。html

2.高效 −React经过对DOM的模拟,最大限度地减小与DOM的交互。前端

3.灵活 −React能够与已知的库或框架很好地配合。java

4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不必定使用 JSX ,但咱们建议使用它。node

5.组件 − 经过 React 构建组件,使得代码更加容易获得复用,可以很好的应用在大项目的开发中。python

6.单向响应的数据流 − React 实现了单向响应的数据流,从而减小了重复代码,这也是它为何比传统数据绑定更简单。react

3 Virtual DOM

DOM (文档对象模型 document object model)webpack

将网页全部内容映射到一颗树形结构的层级对象模型上,浏览器提供对DOM的支持,用户能够是用脚本调用DOM,API来动态修改DOM节点,从而达到修改网页的目的,这种修改是浏览器中完成的,浏览器会根据DOM的改变来重绘改变的DOM节点部分。ios

修改DOM 从新渲染成本过高,前端框架为了提升效率,应尽可能减小DOM重绘,踢出了virtual DOM,全部的修改如今virtual DOM上完成,经过比较算法,找到浏览器DOM之间的差别,使用这个差别操做DOM,浏览器只须要渲染这部分的改变就好了。

React 实现了DOM Diff算法能够高效对比virtual DOM 和 DOM的差别。

4 JSX 语法

JSX 是一种JavaScript和XML混写的语法,是JavaScript的扩展。

1 基本结构

基本结构以下

render(
  <div>
    <div>
      <div>content</div>
    </div>
  </div>,
  document.getElementById('example')
);

2 JSX 规范

1 首字母是小写就是html标记,首字母是大写就是组件
2 要求严格的HTML标记,要求全部标签都必须闭合,br可应该写成<br />,/前面要留一个空格
3 单行省略小括号,多行请使用小括号
4 元素有嵌套,建议多行,注意缩进
5 JSX表达式:使用{}括起来,若是大括号内使用了引号,会当作字符串处理,如<div>'2>1?true:flase'{}</div>里面的表达式就成为了字符串,结果仍然是此值。

二 项目安装和配置文件详解及基本操做

1 安装

将项目开发基础文件test.zip解压。并用这个目录做为项目的根目录,在项目根目录中,执行下面命令们进行和安装,安装完成后,会生成一个node_modules,里面是安装的全部依赖的模块


项目包以下
连接:https://pan.baidu.com/s/1C-ZY9rWU-8ZugE4EwVveWw
提取码:744p

解压目录以下

react项目基础

安装以下

在项目根目录下执行

npm  install

react项目基础

2 配置文件详解

1 package.json 文件

npm init 产生的文件,里面记录项目的信息,全部项目依赖。

{
  "name": "test",
  "version": "1.0.0",
  "description": "magedu blog project",
  "main": "index.js",

  "scripts": {   //项目管理 
    "test": "jest",
    "start": "webpack-dev-server --config webpack.config.dev.js --hot --inline", // start指定启动webpack的 devserver包,--hot 代表是热加载,及修改后直接加载
    "build": "rimraf dist && webpack -p --config webpack.config.prod.js" // build使用webpack构建打包
  },

  "repository": {},   //处理版本管理相关,可经过此处进行链接git服务器用于提交代码至git服务器
  "author": "zhang",
  "license": "MIT",

  "devDependencies": {  //开发时依赖,不会打包到目标文件中,对应npm  install  module-name --save-dev,
    // babel 转义,由于开发用了不少的ES6语法,从6.x开始babel拆分红不少插件,须要什么引入什么,
    "babel-core": "^6.24.1", //核心 
    "babel-jest": "^19.0.0",  
    "babel-loader": "^6.4.1", //webpack的loader,webpack是基于loader的
    "babel-plugin-transform-decorators-legacy": "^1.3.4",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.4.0",  //预设的转换插件
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "css-loader": "^0.28.0",  //css影视相关。包括css-loader,less,less-loader.style-loader 
    "html-webpack-plugin": "^2.28.0",
    "jest": "^19.0.2",
    "less": "^2.7.2",
    "less-loader": "^4.0.3",
    "react-hot-loader": "^4.3.12",  //react热加载插件,但愿改动保存后,直接在页面上直接反馈出来,不须要手动刷新
    "rimraf": "^2.6.2",
    "source-map": "^0.5.6",  //文件打包。js会合并或者压缩,无法调试,用它来看js源文件是什么,source-map-loader也是须要webpack的loader
    "source-map-loader": "^0.2.1",
    "style-loader": "^0.16.1",
    "uglify-js": "^2.8.22",
    "webpack": "^2.4.1", //打包工具
    "webpack-dev-server": "^2.4.2"  //启动一个开发的server 
  },
  "dependencies": {  //运行时依赖,会打包到项目中,对应npm  install  module-name  --save 
    "antd": "^3.10.9", //基于react实现,蚂蚁金服开源的react的UI库,
    "axios": "^0.16.1",  //异步请求支持 
    "babel-polyfill": "^6.23.0",  //解决浏览器api不支持问题
    "babel-runtime": "^6.23.0",
    "mobx": "^4.6.0",  //状态管理库,透明化
    "mobx-react": "^5.4.2",// 和react结合的模块
    "react": "^16.6.3",  //开发的主框架 
    "react-dom": "^16.6.3",  //支持DOM  
    "react-router": "^4.3.1",// 支持路由
    "react-router-dom": "^4.3.1"  //DOM绑定路由
  }
}

2 babel配置

.babelrc babel转义的配置文件

{
  "presets": [
    "react",
    "env",
    "stage-0"
  ],
  "plugins": [
    "transform-decorators-legacy", 
    "transform-runtime",
    "react-hot-loader/babel"
  ]
}

3 webpack配置

webpack.config.dev.js,这是一个符合commonjs的模块

/**
 * Created by magedu on 2017/4/20.
 */

const path = require('path');
const webpack = require('webpack');

module.exports = {  //导出
    devtool: 'source-map',  //导出devtools是source-map
    entry: {  //描述入口,entry 若是是一个字符串,定义就是入口文件,若是是一个数组,里面包含入口文件,另外一个参数能够用来配置一个服务器,此处使用热加载插件,可自动刷新
        'app': [
            './src/index'
        ]
    },
    output: {  //输出,输出目录是_dirname+'dist',名字叫 bundle.js。
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js',
        publicPath: '/assets/'
    },
    resolve: {  //指定解析什么文件类型,这里设置对js文件解析
        extensions: ['.js']
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,  //  node_modules/打包排除目录。这句话必定要有,不然,编译就会把这个目录下全部文件拿进来,此中包含的文件很大
                use: [
                    { loader: 'babel-loader' } //rule中对.js结尾的文件但不在node_modules目录的文件进行热加载loader和转译babel-loader。
                ]
            }, {
                test: /\.css$/,
                use: [
                    { loader: "style-loader" },
                    { loader: "css-loader" },
                ]
            }, 
            {
                test: /\.less$/,
                use: [
                    { loader: "style-loader" },
                    { loader: "css-loader" },
                    { loader: "less-loader" }
                ]
            }
        ]
    },
    plugins: [  //webpack的插件
        new webpack.optimize.OccurrenceOrderPlugin(true),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}})
    ],
    devServer: {
        compress: true,
        port: 3000,  //devserver启动的端口,
        publicPath: '/assets/',
        hot: true,//支持热加载 
        inline: true,
        historyApiFallback: true,
        stats: {
            chunks: false
        },
        proxy: {
            '/api': {  //proxy指定/api开头的路径都代理到http://127.0.0.1:8000去。
                target: 'http://127.0.0.1:8000',
                changeOrigin: true,
                pathRewrite: {'^/api':''}
            }
        }
    }
};

4 vscode 配置

jsconfig.json 是vscode的配置文件,覆盖当前配置。

{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "experimentalDecorators": true
    }
}

上述是全部相关配置文件解释,获取这个文件夹,须要修改name,version,description,须要修改repository仓库地址,须要修改author,license信息,这些信息修改完成后就能够开发了。

3 项目启动与基本操做

1 项目启动

在项目根目录使用npm start 启动devserver便可

npm start

react项目基础

结果以下

react项目基础

上述数字变化的是客户端一直在执行,其JavaScript脚本在本地执行修改DOM树,经过DOM树进行渲染,从而刷新数据

2 测试程序

修改/src/index.js中的代码以下

import React from 'react'; //导入主框架,必需要有
import ReactDom    from  'react-dom';//导入react-som,要进行dom树的操做

class Root  extends  React.Component{  //组件类定义,从React.Component上继承,这个类生成JSXElement对象及就是React元素
  render()  { //渲染函数,返回组件中渲染的内容,注意,此处只能返回惟一一个顶级元素
    return <div>hello world </div>
  }
}

ReactDom.render(<Root  />,document.getElementById('root')); //第一个参数是JSCElement对象,第二个是DOM的Element元素,将React元素添加到DOM的Eelment元素中并进行渲染。还可使用React.createElement建立react元素,第一个参数是React组件或者一个HTML的标签名称如(div,span)

修改后代码以下

import React from 'react';
import ReactDom    from  'react-dom';

class Root  extends  React.Component{
  render()  {
    return <div>hello world </div>
  }
}

ReactDom.render(React.createElement(Root),document.getElementById('root'))

页面结果以下

react项目基础

3 添加子元素

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  render() {
    return  <div>Sub  class </div>
  }
}

class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub />  {/*引用子元素*/}
      </div>
  }
}

ReactDom.render(React.createElement(Root),document.getElementById('root'))

注意 :
1 react 组件的render函数return,只能有一个顶级元素
2 JSX语法是XML,要求全部元素必须闭合,注意<br/>不能写成<br>


结果以下

react项目基础

测试{}里面使用引号

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  render() {
    return  <div>{ 1>2?'flase':'true' }   {/*此处不是字符串是不行的*/}
            <hr />
    "{ 1>2?'flase':'true'}"{/*此处不是字符串是不行的  此处也是能够的 */}
            <hr  />
    "{ "1>2?'flase':'true'" }"</div>; {/*此处不是字符串是不行的  此处会致使存在冲突*/}
        }
      }

class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub />  {/*引用子元素*/}
      </div>
  }
}

ReactDom.render(React.createElement(Root),document.getElementById('root'))

结果以下

react项目基础

三 组件状态和组件间通讯构造器和无状态组件

1 组件状态 state

1 概述

每个react组件都有一个状态变量state,他是一个JavaScript对象,能够为其定义属性来保存值。
若是状态state发生了变化,会触发UI的从新渲染
注意: state是组件本身内部使用的,是组件的私有属性

2 基本定义和操做

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  state = {  //此处必须是一个对象,此处变化会致使调用render后进行渲染,
    x: "test",
    y: ".com"
  }
  render() {
      return  <div>  {this.state.x + this.state.y} </div>  //经过this.stste.xxx来调用此属性
      }
    }

class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub />  {/*引用子元素*/}
      </div>
  }
}

ReactDom.render(React.createElement(Root),document.getElementById('root'))

结果以下

react项目基础

3 修改属性

1 直接修改

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  state = {  //此处必须是一个对象,此处变化会致使调用render后进行渲染,
    x: "test",
    y: ".com"
  }
  render() {
      this.state.x="test100" //修改属性
      return  <div>  {this.state.x + this.state.y} </div>  //经过this.stste.xxx来调用此属性
      }
    }

class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub />  {/*引用子元素*/}
      </div>
  }
}

ReactDom.render(React.createElement(Root),document.getElementById('root'))

结果以下

react项目基础

2 经过内部提供的setState()修改属性

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  state = {  //此处必须是一个对象,此处变化会致使调用render后进行渲染,
    x: "test",
    y: ".com"
  }
  test() {
    this.setState({x:"test100"})
  }
  render() {
      // this.setState({x:"test100"})  //此处不容许在渲染的过程当中修改属性,
      // test();  经过外部定义,内部调用的方式修改也是不能够的,只能经过异步的方式进行修改,以下 
      setTimeout(()=>this.setState({x:"test100"}),5000)  //定义一个箭头函数,输入为空,输出为setState的值,其等待时间为5S进行刷新修改,此处是异步修改
      return  <div>  {this.state.x + this.state.y} </div>  //经过this.stste.xxx来调用此属性
      }
    }

class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub />  {/*引用子元素*/}
      </div>
  }
}

ReactDom.render(React.createElement(Root),document.getElementById('root'))

结果以下

react项目基础

5s后结果为:

react项目基础

4 触发事件基本配置

在项目根目录中index.html中书写以下代码,暂时注释以前代码

<html>
    <head>
        <script type="text/javascript">
            function  getEventTrigger(event) {
                x=event.target;  //从事件中获取元素 
                alert("触发的元素的id是:"+x.id) //输出弹框,并获取id进行组合
            }
        </script>
    </head>   
    <body>
        <h1>测试程序</h1>   
        <div id="test"  onmousedown="getEventTrigger(event)"> {/*此处定义鼠标按下,用于触发事件,并执行对应函数返回对应结果*/}
            点击触发事件,弹出警示框
        </div>    
    </body>   
</html>

结果以下

react项目基础

点击下面的,同一行的都会有影响

react项目基础

恢复代码

react项目基础

在后面的index.js中进行相关配置以下

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  handleClick(event) {
    let  key =event.target; //获取传入参数
    alert("触发的元素的id是:"+key.id)   //抛出相关异常
  }

  render() {
      return  <div  id="test"  onClick={this.handleClick.bind(this)} >{/*此处定义一个按鼠标事件,执行这个事件后,调用指定的函数完成对应操做*/}
      点击触发事件,弹出警示框
      </div>  //经过this.stste.xxx来调用此属性
      }
    }
class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub />  {/*引用子元素*/}
      </div>
  }
}
ReactDom.render(React.createElement(Root),document.getElementById('root'))

结果以下

react项目基础

点击以下

react项目基础

添加state用于触发事件

import React from 'react';
import ReactDom    from  'react-dom';
import { runInThisContext } from 'vm';

class  Sub extends  React.Component{  // 定义子元素 
  state  = {
    flag:true
  }
  handleClick(event) {
    let  key =event.target; //获取传入参数
    this.setState({flag:!(this.state.flag)}) //当触发发生时,修改此处的属性用于下面的显示操做
  }

  render() {
      let  text=(this.state.flag)?"true":"false"  //此处使用三目运算符用于实现相关功能,当为true时,返回true,当this.state.flag为false时返回false
      return  <div  id="test"  onClick={this.handleClick.bind(this)} >{/*此处定义按按鼠标的一个事件,执行这个事件后,调用指定的函数完成对应操做*/}
      <h1>flag={text}</h1>
      </div>  
      }
    }
class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub />  {/*引用子元素*/}
      </div>
  }
}
ReactDom.render(React.createElement(Root),document.getElementById('root'))

结果以下

react项目基础

鼠标点击true和false 转换


分析
Sub 类,它有本身的state属性。当render完成后,网页上会有一个div标签,div标签对象捆绑了一个click事件处理函数,div标签内有文本内容
若是经过剪辑左键,就触发了click方法关联的handleClick函数,在这个函数中对状态值进行修改操做。
状态值state的改变将引起render的重绘。
若是组件本身的state改变了,只会触发本身的render方法重绘,此处是state是私有属性,


注意
{this.handleClick.bind(this)} ,不能外加括号
this.handleClick.bind(this)要绑定this,不然当触发捆绑的函数时,this是函数执行的上下文决定的,this已经不是触发事件的对象了,有多是全局对象。所以须要将this传递进去使得handleClick可以接受正确的参数。

2 props 组件之间通讯和构造器

1 增长属性的三种方式(props是只读的,在该组件内部不能修改)

1 在标签本级标签的引用中加入组件的属性,为这个组件提供外部属性name="test",这个属性会做为一个单一的对象传递给组件,加入到组件的props属性中。


2 在外部进行添加 parent={this} ,注意这个this是在Root元素中,指的是Root组件自己,能够在子组件中调用各类方法完成相应的各类操做。


3 在Root中为使用JSX语法为Sub增长子元素,这些子元素也会被加入到Sub组件的props.children中

2 本级添加方式

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  state  = {
    flag:true
  }
  handleClick(event) {
    let  key =event.target; //获取传入参数
    this.setState({flag:!(this.state.flag)}) //当触发发生时,修改此处的属性用于下面的显示操做
  }

  render() {
      let  text=(this.state.flag)?"true":"false"  //此处使用三目运算符用于实现相关功能,当为true时,返回true,当this.state.flag为false时返回false
      return  <div  id="test"  onClick={this.handleClick.bind(this)} >{/*此处定义按按鼠标的一个事件,执行这个事件后,调用指定的函数完成对应操做*/}
      <h1>  flag: {text}  name: {this.props.name}</h1>
      </div>  
      }
    }
class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub name="test"/>  {/*经过在此标签的调用处传入相关参数*/}
      </div>
  }
}
ReactDom.render(React.createElement(Root),document.getElementById('root'))

结果以下

react项目基础

3 经过添加this来调用当前环境的标签,及符标签的相关状况

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  state  = {
    flag:true
  }
  handleClick(event) {
    let  key =event.target; //获取传入参数
    this.setState({flag:!(this.state.flag)}) //当触发发生时,修改此处的属性用于下面的显示操做
  }

  render() {
      let  text=(this.state.flag)?"true":"false"  //此处使用三目运算符用于实现相关功能,当为true时,返回true,当this.state.flag为false时返回false
      return  <div  id="test"  onClick={this.handleClick.bind(this)} >{/*此处定义按按鼠标的一个事件,执行这个事件后,调用指定的函数完成对应操做*/}

      <h1>  flag: {text}  name: {this.props.name}  {console.log('parent++++++++++',this.props.parent)}  </h1>  {/*经过this.props.parent能够对ROOT中的各类属性和方法进行相关的调用操做,如经过this.props.parent.setState()来修改Root的相关组件状态等操做*/}
      </div>  
      }
    }
class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub name="test"  parent={this}/>  {/*经过在此标签的调用处传入相关参数,此处的this是Root,此处在谁的区域内此this就是谁
      此处是将Root的this指针传递进来*/}
      </div>
  }
}
ReactDom.render(<Root />,document.getElementById('root'));

结果以下

react项目基础

4 调用子标签的children来实现相关处理

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  state  = {
    flag:true
  }
  handleClick(event) {
    let  key =event.target; //获取传入参数
    this.setState({flag:!(this.state.flag)}) //当触发发生时,修改此处的属性用于下面的显示操做
  }

  render() {
      let  text=(this.state.flag)?"true":"false"  //此处使用三目运算符用于实现相关功能,当为true时,返回true,当this.state.flag为false时返回false
      return  <div  id="test"  onClick={this.handleClick.bind(this)} >{/*此处定义按按鼠标的一个事件,执行这个事件后,调用指定的函数完成对应操做*/}

      <h1>  flag: {text}  name: {this.props.name} </h1>
      <hr />
         <h1>sub:{this.props.children}</h1>
      </div>  
      }
    }
class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub name="test"  parent={this}>
       {/*经过在此标签的调用处传入相关参数,此处的this是Root,此处在谁的区域内此this就是谁
      此处是将Root的this指针传递进来*/}
      <div>我是Sub的子标签</div>
      </Sub>
      </div>
  }
}
ReactDom.render(<Root />,document.getElementById('root'));

结果以下

react项目基础

5 修改props

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  state  = {
    flag:true
  }
  handleClick(event) {
    let  key =event.target; //获取传入参数
    this.setState({flag:!(this.state.flag)}) //当触发发生时,修改此处的属性用于下面的显示操做
  }

  render() {
      let  text=(this.state.flag)?"true":"false" 
      return  <div  id="test"  onClick={this.handleClick.bind(this)} >

      <h1>  flag: {text}  name: {this.props.name} </h1>
      <hr />
         <h1>sub:{this.props.children}</h1>
         {this.props.parent={}}  {/*此处修改属性,会致使报错,由于其是只读的*/}
      </div>  
      }
    }
class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub name="test"  parent={this}/>
      </div>
  }
}
ReactDom.render(<Root />,document.getElementById('root'));

结果以下

react项目基础

此处提示是只读属性,不能被修改

对外部的修改管不着。如 this.props.parent.setState({x:y}) 能够修改,此处和python中的元祖相同,若元祖中定义了列表,则虽然元祖是不可变类型,但其中的元素是可变的,仍然是能够修改的。

3 构造器

使用ES6的构造器,要提供一个参数props,并把这个参数使用super传递给父类

import React from 'react';
import ReactDom    from  'react-dom';

class  Sub extends  React.Component{  // 定义子元素 
  constructor(props) {
    console.log('props......',props)
    super(props);//传递到父类。其默认在构造中加入了props属性
    this.state={flag:true} //定义flag
  }
  handleClick(event) {
    let  key =event.target; //获取传入参数
    this.setState({flag:!(this.state.flag)}) //当触发发生时,修改此处的属性用于下面的显示操做
  }

  render() {
      let  text=(this.state.flag)?"true":"false"  //此处使用三目运算符用于实现相关功能,当为true时,返回true,当this.state.flag为false时返回false
      return  <div  id="test"  onClick={this.handleClick.bind(this)} >{/*此处定义按按鼠标的一个事件,执行这个事件后,调用指定的函数完成对应操做*/}
      <h1>  flag: {text}  </h1>
      </div>  
      }
    }
class Root  extends  React.Component{
  render()  {
    return <div>
      hello world 
      <Sub name="test"  parent={this}/>
      </div>
  }
}
ReactDom.render(<Root />,document.getElementById('root'));

结果以下

react项目基础

4 无状态组件定义基本函数

react从 15.0开始支持无状态组件,定义以下

import ReactDOM from 'react-dom';
import React from 'react';
function   Root(props)  {
    return  <div>{props.name}</div>
}
ReactDOM.render(<Root name="test" />,document.getElementById('root'));  

结果以下

react项目基础

修改代码以下

import ReactDOM from 'react-dom';
import React from 'react';
let Root = props   =>  <div>{props.name}</div>
ReactDOM.render(<Root name="test" />,document.getElementById('root'));  

结果和上面相同

5 总结

state 是私有属性,组件外部没法直接访问,能够修改state,但建议使用setState方法。

props是公有public属性,组件外也能够访问,可是是只读属性

四 组件的生命周期

1 组件的三个状态

组件的声明周期可分为三个状态
1 Mounting:已插入真实DOM
2 Updating:正在被从新渲染
3 Unmounting:已移出真实DOM

2 组件的生命周期方法

1 装载组件触发

1 componentWillMount:在渲染以前调用,在客户端也在服务端,只会在装载以前调用一次


2 componentDidMount:在第一次渲染后调用,只在客户端,以后组件已经生成了对应的DOM结构,能够经过this.getDOMNode()来进行访问,若是你想和其余JavaScript框架一块儿使用,能够在这个方法中调用setTimeout,setInterval或者发送AJAX请求等操做(放置异步调用阻塞UI),只在装载完成后调用一次,在render以后。

2 更新组件触发

这些组件不会在首次render组件的周期调用
1 componentWillReceiveProps(nextProps)在组件接收到一个新的props时被调用,这个方法在初始化render时不会被调用。如上述的经过外部传入name的状况会调用此中方式


2 shouldComponentUpdate(nextProps,nextState)返回一个布尔值,在组件接收到新的props或者state时被调用,在初始化时或者使用forceUpdate时不会被调用
做用:
1 能够在你确认不须要更新组件时使用
2 若是设置为false,就是不容许更新组件操做。那么componentWillUpdate,componentWillUpdate不会执行


3 componentWillUpdate(nextProps,nextState)在组件接收到新的props或者state但仍是没有render时被调用,在初始化时不会被调用


4 componentDidUpdate(prevProps,prevState)在组件完成更新后当即调用,在初始化时不会被调用。

3 卸载组件触发

1 componentWillUnmount 在组件从DOM中移除的时候当即被调用

3 生命周期图

react项目基础

上图可知,其construtor构造器是最先执行的函数
触发更新生命周期函数,须要经过更新state和props,

相关代码以下

import React from 'react';
import ReactDOM from 'react-dom';
class Sub  extends  React.Component{
  constructor(props)  {
    super(props) 
      console.log('sub Constructor')
      super(props);
      this.state={count: 0};  //定义变量
    }
  handleClick(event) {
    this.setState({count:this.state.count+1});
  }
  render(){
    console.log('Sub render');
    return  (<div  id='sub' onClick={this.handleClick.bind(this)}> sub's count={this.state.count} </div>)
  }
  componentDidMount(){
        //第一次render以后
    console.log('Sub  componentDidMount')
  }
  componentWillMount(){
     //constructoir以后,第一次调用render
    console.log('Sub  componentWillMount')
  }
  componentWillUnmount(){
    //清理工做
    console.log('Sub  componentWillUnmount')
  }
}
class  Root extends  React.Component  {
  constructor(props) {
    console.log('Root  Constructor')
    super(props); //调用父类对象
    this.state={};  // 定义一个对象
  }
  render(){
    return  (<div>hello world
      <hr />
      <Sub />
    </div>);
  }
}
ReactDOM.render(<Root/>,document.getElementById('root'));

结果以下

react项目基础

处理过程:父构造---子构造-- componentWillMount ---render----componentDidMount

import React from 'react';
import ReactDOM from 'react-dom';
class Sub  extends  React.Component{
  constructor(props)  {
    super(props) 
      console.log('sub Constructor')
      super(props);
      this.state={count: 0};  //定义变量
    }
  handleClick(event) {
    this.setState({count:this.state.count+1});
  }
  render(){
    console.log('Sub render');
    return  (<div  id='sub' onClick={this.handleClick.bind(this)}> 
    sub's count={this.state.count} </div>)
  }
  componentDidMount(){
    //constructoir以后,第一次调用render
    console.log('Sub  componentDidMount')
  }
  componentWillMount(){
    //第一次render以后
    console.log('Sub  componentWillMount')
  }
  componentWillUnmount(){
    //清理工做
    console.log('Sub  componentWillUnmount')
  }
  componentWillReceiveProps(nextProps)  {
    //props变动时,接到新的props了,交给shouldcompupdate
    //props 组件内只读。只能从外部修改
    console.log(this.props);
    console.log(nextProps);
    console.log('this componentWillReceiveProps',this.state.count)
  }
  shouldComponentUpdate(nextProps,nextState) {
    console.log('Sub  shouldComponentUpdate',this.state.count,nextState);
    return true; //return 为false将拦截更新
  }
  componentWillUpdate(nextProps,nextState){
    // 赞成更新后,真正更新前,执行的动做 
    console.log('Sub  componentWillUpdate',this.state.count,nextState);
  }
  componentDidUpdate(prevProps,prevState){
    //赞成更新后,真正更新后调用
    console.log('Sub  componentDidUpdate',this.state.count,prevState);
  }

}

class  Root extends  React.Component  {
  constructor(props) {
    console.log('Root  Constructor')
    super(props); //调用父类对象
    this.state={flag:true,name:'root'};  // 定义一个对象
  }
  handleClick(event)  {
    this.setState(
      {flag: !this.state.flag,
      name:this.state.flag?this.state.name.toLowerCase():this.state.name.toUpperCase() // 切换名字大小写
      }
    );
  }
  
  render(){
    return  (<div id='root'  onClick={this.handleClick.bind(this)}>
      my  name is  {this.state.name}<hr />
      <Sub />  {/*父组件的render,会引发下一级组件的更新流程,致使props从新发送,即便子组件props没有改变过*/}
    </div>);
  }
}
ReactDOM.render(<Root/>,document.getElementById('root'));

结果以下,须要点击鼠标。下面的显示和上面的都会动,子组件是镶嵌在父组件中的,所以其会总体变化。子元素在父元素的区域内的。

react项目基础

相关区域以下

父元素响应区域

react项目基础

子元素响应区域

react项目基础

调用render函数的状况下也没刷新,由于发现虚拟DOM和DOM之间是没有差别的,所以其子区域不须要重绘


点击父元素,子元素会从新渲染,会受到影响,由于子元素的props会被重置,其是从父元素传递过去的,其会从新走一会儿元素走的路。

react项目基础

4 总结

componentWillMount 第一次装载,在首次render以前,如控制state,props
componentDidMount 第一次装载接受,首次render以后,例如控制state,props

componentWillReceiveProps 在组件内部,props是只读不可变的,可是这个函数能够接受到新的props,能够对props作一些处理,如this.props={name:'224523542w43'}

componentWillReceiveProps 触发,也会走shouldComponentUpdate

shouldComponentUpdate判断是否须要组件更新,就是是否render,精确的控制,提升性能

componentWillUpdate在首次render外,每次render前执行,componentWillUpdate在render以后调用。

不过,大多数状况向,用不上这些函数,这些钩子函数是为了精确控制使用。

相关文章
相关标签/搜索