您好,登录后才能下订单哦!
React 是一个用于构建用户界面的 JAVASCRIPT 库。
React 主要用于构建UI,很多人认为 React 是 MVC 中的 V。
React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。
React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使用它。
React 是解决前端MVC框架中的view视图层的问题
M 是指数据模型,V是指显示的问题,C是指控制的问题
1.声明式设计 −React采用声明范式,可以轻松描述应用。
2.高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
3.灵活 −React可以与已知的库或框架很好地配合。
4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。
5.组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
6.单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
DOM (文档对象模型 document object model)
将网页所有内容映射到一颗树形结构的层级对象模型上,浏览器提供对DOM的支持,用户可以是用脚本调用DOM,API来动态修改DOM节点,从而达到修改网页的目的,这种修改是浏览器中完成的,浏览器会根据DOM的改变来重绘改变的DOM节点部分。
修改DOM 重新渲染成本太高,前端框架为了提高效率,应尽量减少DOM重绘,踢出了virtual DOM,所有的修改现在virtual DOM上完成,通过比较算法,找到浏览器DOM之间的差异,使用这个差异操作DOM,浏览器只需要渲染这部分的改变就行了。
React 实现了DOM Diff算法可以高效对比virtual DOM 和 DOM的差异。
JSX 是一种JavaScript和XML混写的语法,是JavaScript的扩展。
基本结构如下
render(
<div>
<div>
<div>content</div>
</div>
</div>,
document.getElementById('example')
);
1 首字母是小写就是html标记,首字母是大写就是组件
2 要求严格的HTML标记,要求所有标签都必须闭合,br可应该写成<br />,/前面要留一个空格
3 单行省略小括号,多行请使用小括号
4 元素有嵌套,建议多行,注意缩进
5 JSX表达式:使用{}括起来,如果大括号内使用了引号,会当做字符串处理,如<div>'2>1?true:flase'{}</div>里面的表达式就成为了字符串,结果仍然是此值。
将项目开发基础文件test.zip解压。并用这个目录作为项目的根目录,在项目根目录中,执行下面命令们进行和安装,安装完成后,会生成一个node_modules,里面是安装的所有依赖的模块
项目包如下
链接:https://pan.baidu.com/s/1C-ZY9rWU-8ZugE4EwVveWw
提取码:744p解压目录如下
安装如下
在项目根目录下执行
npm install
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绑定路由
}
}
.babelrc babel转义的配置文件
{
"presets": [
"react",
"env",
"stage-0"
],
"plugins": [
"transform-decorators-legacy",
"transform-runtime",
"react-hot-loader/babel"
]
}
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':''}
}
}
}
};
jsconfig.json 是vscode的配置文件,覆盖当前配置。
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"experimentalDecorators": true
}
}
上述是所有相关配置文件解释,获取这个文件夹,需要修改name,version,description,需要修改repository仓库地址,需要修改author,license信息,这些信息修改完成后就可以开发了。
在项目根目录使用npm start 启动devserver即可
npm start
结果如下
上述数字变化的是客户端一直在执行,其JavaScript脚本在本地执行修改DOM树,通过DOM树进行渲染,从而刷新数据
修改/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'))
页面结果如下
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>
结果如下
测试{}里面使用引号
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组件都有一个状态变量state,他是一个JavaScript对象,可以为其定义属性来保存值。
如果状态state发生了变化,会触发UI的重新渲染
注意: state是组件自己内部使用的,是组件的私有属性
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'))
结果如下
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'))
结果如下
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'))
结果如下
5s后结果为:
在项目根目录中index.html中书写如下代码,暂时注释之前代码
<html>
<head>
<script type="text/javascript">
function getEventTrigger(event) {
x=event.target; //从事件中获取元素
alert("触发的元素的id是:"+x.id) //输出弹框,并获取id进行组合
}
</script>
</head>
<body>
<h2>测试程序</h2>
<div id="test" onmousedown="getEventTrigger(event)"> {/*此处定义鼠标按下,用于触发事件,并执行对应函数返回对应结果*/}
点击触发事件,弹出警示框
</div>
</body>
</html>
结果如下
点击下面的,同一行的都会有影响
恢复代码
在后面的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'))
结果如下
点击如下
添加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)} >{/*此处定义按按鼠标的一个事件,执行这个事件后,调用指定的函数完成对应操作*/}
<h2>flag={text}</h2>
</div>
}
}
class Root extends React.Component{
render() {
return <div>
hello world
<Sub /> {/*引用子元素*/}
</div>
}
}
ReactDom.render(React.createElement(Root),document.getElementById('root'))
结果如下
鼠标点击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能够接受正确的参数。
1 在标签本级标签的引用中加入组件的属性,为这个组件提供外部属性name="test",这个属性会作为一个单一的对象传递给组件,加入到组件的props属性中。
2 在外部进行添加 parent={this} ,注意这个this是在Root元素中,指的是Root组件本身,可以在子组件中调用各种方法完成相应的各种操作。
3 在Root中为使用JSX语法为Sub增加子元素,这些子元素也会被加入到Sub组件的props.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)} >{/*此处定义按按鼠标的一个事件,执行这个事件后,调用指定的函数完成对应操作*/}
<h2> flag: {text} name: {this.props.name}</h2>
</div>
}
}
class Root extends React.Component{
render() {
return <div>
hello world
<Sub name="test"/> {/*通过在此标签的调用处传入相关参数*/}
</div>
}
}
ReactDom.render(React.createElement(Root),document.getElementById('root'))
结果如下
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)} >{/*此处定义按按鼠标的一个事件,执行这个事件后,调用指定的函数完成对应操作*/}
<h2> flag: {text} name: {this.props.name} {console.log('parent++++++++++',this.props.parent)} </h2> {/*通过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'));
结果如下
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)} >{/*此处定义按按鼠标的一个事件,执行这个事件后,调用指定的函数完成对应操作*/}
<h2> flag: {text} name: {this.props.name} </h2>
<hr />
<h2>sub:{this.props.children}</h2>
</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'));
结果如下
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)} >
<h2> flag: {text} name: {this.props.name} </h2>
<hr />
<h2>sub:{this.props.children}</h2>
{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'));
结果如下
此处提示是只读属性,不能被修改
对外部的修改管不着。如 this.props.parent.setState({x:y}) 可以修改,此处和python中的元祖相同,若元祖中定义了列表,则虽然元祖是不可变类型,但其中的元素是可变的,仍然是可以修改的。
使用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)} >{/*此处定义按按鼠标的一个事件,执行这个事件后,调用指定的函数完成对应操作*/}
<h2> flag: {text} </h2>
</div>
}
}
class Root extends React.Component{
render() {
return <div>
hello world
<Sub name="test" parent={this}/>
</div>
}
}
ReactDom.render(<Root />,document.getElementById('root'));
结果如下
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'));
结果如下
修改代码如下
import ReactDOM from 'react-dom';
import React from 'react';
let Root = props => <div>{props.name}</div>
ReactDOM.render(<Root name="test" />,document.getElementById('root'));
结果和上面相同
state 是私有属性,组件外部无法直接访问,可以修改state,但建议使用setState方法。
props是公有public属性,组件外也可以访问,但是是只读属性
组件的声明周期可分为三个状态
1 Mounting:已插入真实DOM
2 Updating:正在被重新渲染
3 Unmounting:已移出真实DOM
1 componentWillMount:在渲染之前调用,在客户端也在服务端,只会在装载之前调用一次
2 componentDidMount:在第一次渲染后调用,只在客户端,之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问,如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout,setInterval或者发送AJAX请求等操作(放置异步调用阻塞UI),只在装载完成后调用一次,在render之后。
这些组件不会在首次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)在组件完成更新后立即调用,在初始化时不会被调用。
1 componentWillUnmount 在组件从DOM中移除的时候立即被调用
上图可知,其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'));
结果如下
处理过程:父构造---子构造-- 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'));
结果如下,需要点击鼠标。下面的显示和上面的都会动,子组件是镶嵌在父组件中的,因此其会整体变化。子元素在父元素的区域内的。
相关区域如下
父元素响应区域
子元素响应区域
调用render函数的情况下也没刷新,因为发现虚拟DOM和DOM之间是没有差异的,因此其子区域不需要重绘
点击父元素,子元素会重新渲染,会受到影响,因为子元素的props会被重置,其是从父元素传递过去的,其会重新走一下子元素走的路。
componentWillMount 第一次装载,在首次render之前,如控制state,props
componentDidMount 第一次装载接受,首次render之后,例如控制state,propscomponentWillReceiveProps 在组件内部,props是只读不可变的,但是这个函数可以接受到新的props,可以对props做一些处理,如this.props={name:'224523542w43'}
componentWillReceiveProps 触发,也会走shouldComponentUpdate
shouldComponentUpdate判断是否需要组件更新,就是是否render,精确的控制,提高性能
componentWillUpdate在首次render外,每次render前执行,componentWillUpdate在render之后调用。
不过,大多数情况向,用不上这些函数,这些钩子函数是为了精确控制使用。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。