react、JSX编译原理、生命周期、属性、状态改变、建立组件、复合组件间的信息传递、受控和非受控组件、react脚手架

React是Facebook公司研发的一款JS框架(MVC:Model View Controller) 经过数据的改变来影响视图javascript

一、React脚手架

React是一款框架:具有本身开发的独立思想 - 划分组件开发css

前端工程化开发:html

  • 基于框架的组件/模块化开发
  • 基于webpack的自动部署

webpack来完成以上内容(自动化):前端

  • 基于路由的spa单页面开发
  • 区分开发环境和生产环境
  • 安装babel完成ES6编写代码(上线时,ES6编译成ES5)
  • 安装css、style、file等处理器,处理合并压缩的
  • 编译less,sass等预编译语言
  • 安装webpack-dev-server ,能够在开发环境下,编译后自动建立服务,打开浏览器,当代码修改后,自动保存编译,页面自动刷新
  • ....

脚手架 配置webpack相对复杂,咱们须要安装不少的包,还须要写不少相对复杂的配置,这时候脚手架应运而生,用来提高咱们开发的效率vue

vue:vue-cli react:create-react-app(应用)java

2、安装

一、npm install create-react-app -g // 安装到全局能用命令 (npm root -g 查看全局npm安装目录) 二、create-react-app demo1 // 项目名称demo1,名称只能(/^[a-z0-9_-]$/)node

脚手架生成目录中的一些内容:react

一、node_module 当前项目中依赖的包 .bin 本地项目中可执行的命令,在package.json的scripts中配置的对应的脚本便可(还有一个是react-scripts命令) 二、public 存放当前项目的页面(单页面应用放index.html便可,多页面根据本身需求放置须要的页面)webpack

在react中,全部的逻辑都是在JS中完成的(包括页面机构的建立),若是想给当前的页面导入一些css样式后者img图片等内容,咱们有两种方式:ios

(1)、在JS中基于ES6 Module模块规范,使用import引入,这样webpack在编译合并JS的时候,会把导入的资源文件等插入到页面的机构中(绝对不能在js管控的结构中经过相对目录./ 或者../ 导入资源,由于在webpack编译的时候,地址就不在是以前的相对地址要用绝对地址

(2)、若是不想在js中导入(JS中导入的资源最后都是基于webpack编译),咱们也能够把资源手动的在html中代入,可是html最后也要基于webpack编译,导入的地址也不建议写相对地址,而是使用%PUBLIC_URL%写成绝对地址

<link rel="manifest" href="%PUBLIC_URL%/reset.min.css">
复制代码

三、src 项目结构中最主要的目录,由于后期全部的JS、路由、组件等都是放到这里面(包括须要编写的css或者图片等) index.js 是入口文件 四、.gitignore git的忽略文件 五、package.json 当前项目的配置清单

"dependencies": {
    "react": "^16.4.1",
    "react-dom": "^16.4.1",
    "react-scripts": "1.1.4"
  },
复制代码

基于脚手架生成工程目录,自动帮咱们安装了三个模块:

  • react 、
  • react-dom、
  • react-scripts(集成了webpack须要的内容babel,css处理,eslint, webpack....,注意:没有less、sass)

package.json:

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
复制代码

可执行的脚本

npm run start 或者 yarn start

yarn start

  • 建立一个默认端口号为3000 ,协议为http的web服务
  • 按照webpack.config.dev.js把项目编译
  • 打开浏览器预览咱们的项目
  • 项目修改时候,自动从新编译,浏览器页面自动刷新,展现最新的效果

yarn build:

  • 基于webpack.config.prod.js 把项目进行编译打包
  • 生成一个build文件夹,存放最后打包的文件>- 生成一个build文件夹,存放最后打包的文件
  • 部署上线的时候,只须要把build的内容发布便可

3、React脚手架的深刻剖析

create-react-app 脚手架为了让结构目录清晰,把安装的webpack及配置文件都集成在了react-scripts模块中,放到了node_modules中 可是真实项目中,咱们须要在脚手架默认安装的基础上,额外安装一些咱们须要的模块,例如react-router-domaxios、还有lessless-loader

状况一:若是咱们安装其余的组件,可是安装成功后不须要修改webpack的配置项,此时咱们直接安装,调取使用就行,好比react-router-dom 、axios等

状况二:咱们安装的插件是基于webpack处理的,也就是须要把安装的模块配置到webpack中(从新修改webpack配置项了) 一、首先须要把隐藏到node_module中的配置项暴露到项目中 yarn eject 首先会肯定是否确认执行eject,这个操做不可逆转,一旦暴露出来配置项,就没法再隐藏了 若是还有未提交到历史区的内容,须要先提交,而后才能eject 二、再去修改对应的配置项 暴露后,项目目录中多了两个文件夹: config:存放的是webpack的配置文件 (1)webpack.config.dev.js 开发环境下的配置项(yarn start) (2)webpack.config.prod.js 生产环境下的配置项(yarn build) scripts:存放的是可执行脚本的JS文件 (1)start.js: yarn start 执行的就是这个JS (2)build.js: yarn build 执行的就是这.个JS

咱们预览项目的时候,也是基于webpack编译,把编译后的内容放到浏览器中运行,因此若是项目中使用了less,咱们须要修改webpack配置项,在配置项中加入less的编译工做,这样后期预览项目,首先基于webpack把less编译为css

set HTTPS=true && npm start 开启HTTPS协议模式 set PORT=1111 && npm start 修改默认端口号

4、渐进式框架

一种渐进式框架设计思想,通常框架中都包含了不少内容,这样致使框架的体积过于臃肿 拖慢加载的速度, 真实项目中,咱们使用一个框架,不必定用到全部的功能,此时咱们应该把框架的功能进行拆分,用户想用什么,让其本身自由组合便可--"渐进式框架"

全家桶:渐进式框架N多部分的组合 vue全家桶:vue、vue-cli、vue-router、vuex、axios、vue-element 、vant、 react全家桶:react、react-react-app、react-dom、react-router、redux、react-redux、axios、ant、dva、saga、mobx

一、React

react的核心部分,提供了Component类能够进行组件开发,提供了钩子函数(生命周期),全部的生命周期函数都是基于回调函数完成的

二、React-dom:

raect独有的,把JSX语法,渲染为真实DOM(可以放到页面中展现的机构都叫作真实的DOM)的组件

react框架都是在JS中进行的,而后经过webpack编译,再放到浏览器中编译

在index.js这个入口文件:

import React from 'react';
import ReactDOM from 'react-dom';
// import ReactDOM,{render} from 'react-dom';
// 从react-dom中导入一个reactDOM,逗号后面的内容是把ReactDOM这个对象进行结构

let data ='zufeng',
    root = document.querySelector("#root");

ReactDOM.render(<div id="box">hello world!{data}</div>,root,()=>{
    // 回调,通常不用
    let oBox = document.querySelector("#box");
    console.log(oBox.innerHTML);
});
复制代码

2.一、JSX(也叫react元素):

JSX语法的渲染使用的是ReactDOM.render: ReactDOM.render([jsx],[container],[callback]);

jsx:react独有的语法, JavaScript+xml(HTML),和咱们以前拼接的字符串相似,都是把html结构代码和js代码或者数据混合在一块儿了,可是他不是字符串 container:容器,咱们想把元素放到页面中的哪一个容器中 callback:当把容器放到页面中呈现触发的回调函数

jsx语法特色:

一、不建议咱们 直接把jsx直接放到body中,而是放在本身建立一个容器中,通常咱们都放在一个id为root的div中

ReactDOM.render(<section><h2>内容</h2></section>,root)
复制代码

二、把数据嵌入到jsx中 在JSX中出现的{}是存放JS的,要求JS代码执行完成须要有返回结果(JS表达式),不能直接放一个对象数据类型的

let name = 'zhufeng'     // 基本数据类型的值
ReactDOM.render(<section><h2{name}</h2></section>,root)

let xx = {name:'xxxx'}
ReactDOM.render(<section><h2{xx}</h2></section>,root)  // 报错
复制代码
  • 不能直接放一个对象数据类型的值(对象((除了给style赋值)),数组(若是只有基本值或者jsx除外),函数都不行)
ReactDOM.render(<ul>
   {
     data.map((item,index)=>{
        return <li key={index}>{item.title}</li>
     })
   }
</ul>,root)
复制代码
  • 能够是基本类型的值(布尔类型什么都不显示,null,undefined也是jsx元素,表明的是空)
  • 循环判断语句都不行,可是支持三元运算符

三、循环数组穿件jsx元素,须要给建立的元素设置惟一的key值(当前本次惟一便可) 四、只能出现一个根元素 五、给元素设置样式类用的是className而不是class 六、style中不能直接写样式字符串,须要基于一个样式对象来遍历赋值 七、能够给JSX元素设置属性: => 属性值对应大括号中,对象、函数均可以放(也能够放JS表达式) =>style属性值必须是对象(不能是字符串)<li style={{color:'#fff'}}></li> =>class 用className代替

ReactDOM.render(<h1 id={'box'} className="box" style={{color:'red'}}>我是标题</h1>);
复制代码

三、渲染原理(react的核心原理之一)

JSX虚拟DOM变为真实的DOM(react的核心原理之一)

let  styleObj = {color:'red'};
ReactDOM.render(<h1 id="titleBox" className='title' style={styleObj.color}></h1>)
复制代码

JSX渲染机制:JSX->真实DOM

一、基于babel babel-loader babel-present-react-app把JSX语法编译为React.createElement([type],[props],[children])结构 =>React.createElement中至少有两参数, type:第一参数的标签(字符串) props:属性对象(没有就是null) 其余的:都是子元素内容(只要子元素是html,就会变成新的createElement)

var styleObj = { color: 'red' };
ReactDOM.render(React.createElement('h1', { id: 'titleBox', className: 'title', style: styleObj.color }));
复制代码

二、执行React.createElement(....),建立一个对象(虚拟DOM)

=>key 和ref 都是createElement中的Prop提取出来的 =>props:{ chiledren:存放本身子元素的(没有子元素就没有这个属性),若是有多个子元素,就以数组的形式存储信息 } 三、ReactDOM.render(JSX语法最后生成的对象,container,callback),基于render方法把生成的对象动态建立为DOM元素,插入到指定的容器中

四、组件

无论vue仍是react框架,设计之初都是指望咱们按照“组件 / 模块管理” 的方式来构建程序的,也就是一个程序划分一个个的组件来单独管理 src -> component:这个文件夹下存放的就是开发用的组件 【优点】 一、有助于多人协助开发 二、组件能够复用 ....

react 中建立组件有两种方式:

一、函数式声明组件

(1)函数返回结果是一个新的JSX(也就是当前组件的JSX结构) (2)props变量存储的值是一个对象,包含了调取组件时候传递的属性值,不传递的话是个空对象

知识点

createElement遇到一个组件,返回的对象中:type就不是字符串标签名了,而是一个函数(类),可是属性仍是存在props中

render渲染的时候,咱们须要作处理:

首先判断type的类型, 若是是字符串,就建立一个元素标签, 若是函数或者类,就把函数执行,把props中的每一项(包含children)传递给函数 在执行的时候,把函数中return的JSX转换为新的对象(经过createElement),把这个对象返回:紧接着render按照以往的渲染方式,建立DOM元素,插入到指定的容器中便可

单闭合和双闭合组件的区别,双闭合组件中能够放子孙元素

函数式声明特色:

一、会把基于createElement解析出来的对象中的props做为参数传递给组件(能够完成屡次调取组件传递不一样的信息) 二、一旦组件调取成功,返回的jsx就会渲染到页面中,可是后期不经过从新调取组件或者获取DOM元素操做的方式,很难再把渲染好组件中的内容更改 -->"静态组件"

//Dialog.js
import React from 'react';    // 每一个组件必须引入,由于须要基于它的create-element把JSX进行解析渲染
export default function Dialog(props) {
    //props:调取组件的时候传递进来的属性信息(可能包含className、style、id、可能有children)
    let {con, lx = 0, children,style={}} = props,
        title = lx === 0 ? '系统提示' : '系统警告';
    //children 可能有,可能没有,多是个值,也多是个数组,每一项多是字符串也多是个对象等,都表明双闭合组件的子孙元素
    return <section style={style}>
        <h2>{title}</h2>
        <div>{con}</div>
        {/*一、把属性中的子元素,放到组件中的指定位置*/}
        {/*{children}*/}
        {/*二、也可使用react中专门遍历children的方法*/}
            {children.map(item => item)}
            {/*// {React.Children.map(children,item=>item)}*/}
        </section>
}

// index.js

import React from 'react';
import ReactDOM from 'react-dom';
// 公共css放index.js中,这样在其余组件中也可使用(webpack会把全部的组件最后都编译到一块儿,index是主入口)
// import 'static/css/reset.min.css'
import 'bootstrap/dist/css/bootstrap.css'  // 须要导入未通过压缩的文件,不然报错(真实项目中bootstrap已是过去式了,后期用ant)

import Dialog from "./component/Dialog-bootstrap";

ReactDOM.render(<main>
    <Dialog content ='马少帅很帅'/>
    <Dialog type ={2} content='系统错误了'/>
    <Dialog type = '请登陆' content={
        '新的JSX语法'
    }>
        <div>
            <input type="text" className='form-control' placeholder='请输入用户名'/><br/>
            <input type="password" placeholder='请输入密码'/>
        </div>
        <br/>
        <button className='btn btn-success'>登陆</button>
        <button className='btn btn-danger'>取消</button>
    </Dialog>
</main>,root);
复制代码

二、继承component类来建立组件

基于component把JSX转换为一个对象,当render渲染这个对象的时候,遇到type是一个函数或者类,不是直接建立元素,而是把方法执行,

  • 若是就是函数声明的组件,就把它当作普通函数执行(方法中的this是undefined),把函数返回的JSX元素(也是解析后的对象)进行渲染
  • 若是是类声明式的组件,会把当前类new执行,建立类的一个实例(当前本次调用的组件就是它的实例)执行constuctor以后,会执行this.render(),把rende返回的JSX拿过来渲染,因此“类声明式的组件,必须有一个render的方法,方法中须要返回一个JSX元素” 可是无论哪种方式,最后都会把解析出来的props属性对象做为实参传递给对应的函数或者类

特色: 一、调取组件至关于建立类的实例(this),把一些私有的属性挂载到实例上了,这样组件内容全部的方法中均可以基于实例获取这些值(包括:传递的属性和本身管理的状态) 二、有本身的状态管理,当状态改变的时候,react会从新渲染视图(差别更新:基于DOM-DIFF只把有差别的部分渲染)

import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types'  // facebook是公司开发的一个插件,基于这个插件咱们能够给组件传的属性设置规则,设置的规则不会影响页面的渲染,能够不加
// 可是会在控制台抛出警告错误

class Dialog extends React.Component{
   // this.props只读的,咱们没法在方法中修改它的值,可是能够给其设置默认值或者设置一些规则(例如:设置是不是必须传递的以及传递的值的类型等)
   static  defaultProps ={
        lx:"系统提示"
   };
   static propTypes = {
        // 设置属性规则,若是传的不是这个规则的,不影响页面的渲染,只是会在控制台抛出警告错误
        // con: PropTypes.string   传递的内容必须是字符串
        con:PropTypes.string.isRequired  // 传递的内容是字符串,并且还必须是传递
   };
   constructor(props){    // props context updater
       // props:当render渲染而且把当前类执行建立实例的时候,会把以前JSX解析出来的props对象中的信息(可能有children)传递给参数props  =>  "调取组件传递的属性"

       // props若是不传,super也不传,除了constructor中不能直接使用this.props,其余声明周期函数中均可以使用(也就是执行完成constructor,
       // react已经帮咱们把传递的属性接收,而且挂载到实例上了)

       super(props);  // extends继承,一旦使用了constructor,第一行位置必须设置super执行,至关于React.Component.call(this),也就是call继承,把父类私有的属性继承过来
       // this.props:属性集合
       // this.refs:ref集合(非受控组件中用到)
       // this.context:上下文

       // - 若是super(props); 在继承父类私有的时候,就把props挂载到this实例上了,这个this只是constructor中的this,不影响原型上的this,写不写都行
       // - 若是只写super() 虽然建立实例的时候把属性传递过来了,可是并无传递父组件,也就是没有把属性挂载到实例上,使用this.props获取的结果是undefined
       // -
       console.log(props);
       // AA = 12;  设置私有属性,可是不符合ES6语法,须要babel-preset-react编译
       // fn=()=>{}  设置一个箭头函数,可是不符合ES6语法,须要babel-preset-react编译
   }

   render(){
       // render必须写还必须有返回的东西
       return <section>
           <h3>系统提示</h3>
           <div>
               zhufeng
           </div>
       </section>
   }
}

ReactDOM.render(<div>
    <Dialog>
        <span>d</span>
    </Dialog>
</div>,root);
复制代码

组件中的属性(this.props)是调取组件的时候(建立类实例的时候)传递给组件的信息,这部分信息是只读的(只能获取不能修改)-> "组件的属性是只读的"

Object.defineProperty(this.props,'cont',{
   writable:true
});
复制代码

用这种方法也改不了


组件部分的总结

建立组件有两种方式:一是“函数式”,一是“建立类式”

函数式

一、操做简单 二、能实现的功能也很简单,只是简单的调取和返回

建立类式

一、操做相对复杂一点,可是也能够实现更为复杂的业务功能 二、可以使用生命周期函数操做业务 三、函数式能够理解为静态组件(组件中内容调取的时候,就已经固定了,很难再修改),而类这种方式,能够基于组件内部的状态来动态更新渲染的内容:

所谓函数组件是静态组件,和执行普通方法同样,调取一次组件,就把组件中内容获取到,若是不从新调取组件,显示内容是不发生改变的


【需求】实现页面上时间的走动

一、函数式的

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

function Clock() {
  return <div>
      <h3>当前北京时间为:</h3>
      <div style={{color:'red',fontWeight:'bold'}}>{new Date().toLocaleString()}</div>
  </div>
}
/*每隔一秒从新调取组件*/
setInterval(()=>{
    ReactDOM.render(<Clock/>,root);
},1000)
//适用于组件内容不会再次发生改变的状况下
复制代码

二、建立类式

class Clock extends React.Component{
   constructor(){
       super();
       // 初始化组件状态(都是对象类型):要求咱们在constructor中把后期须要使用的状态信息所有初始一下(约定俗称的语法规范)
       this.state = {
           time:new Date().toLocaleString(),
       }
   }
   componentDidMount(){
       //react生命周期函数之一:第一次组件渲染完成后触发(咱们只须要间隔1000ms把state状态中的time数据改变,这样react会帮咱们组件中的部门内容进行渲染)

       setInterval(()=>{
           // this.state.time = new Date().toLocaleString(); //虽然下面的定时器能够修改状态,可是不会通知react从新渲染页面,这样不行
           //修改组件的状态
            // 一、修改部分状态:会用咱们传递的对象和初始化的state进行匹配,只把咱们传递的属性进行修改,没有传递的依然保留原始的状态信息(部分修改)
            // 二、修改状态修改完成,会通知react把组件进行从新渲染
           
           this.setState({
               time:new Date().toLocaleString(),
           },()=>{
               /*当通知react把须要从新渲染的JSX元素从新渲染完成后,执行的回调操做(相似于生命周期中的componentDidUpdate)项目中通常使用钩子函数*/
               // 设置回调的缘由是:通知完就直接往下执行,render方法是个异步操做
           });
       },1000)
   }
   render(){
       return <div> <h3>当前北京时间为:</h3> <div style={{color:'red',fontWeight:'bold'}}>{this.state.time}</div> </div>
   }
}
ReactDOM.render(<Clock/>,root);
复制代码

React中的组件有两个很是重要的概念:

一、组件的属性:[只读]调取组件的时候传递进来的信息 二、组件的状态:[读写]本身在组件中设定和规划的(只有类声明式组件才有状态的管控你,函数式组件声明不存在状态的管理)

组件状态相似于VUE中的数据驱动:

咱们数据绑定的时候是基于状态值绑定,当修改组件状态后,对应的JSX元素也会跟着从新渲染(差别渲染:只把数据改变的部分从新渲染,基于DOM-DIff算法完成)

当代前端框架最重要的核心思想就是:“数据操做视图(视图影响数据)”,让咱们告别JQ手动操做DOM的时代,咱们之后只须要改变数据,框架会帮咱们从新渲染视图,从而减小直接操做DOM(提升性能,也有助于开发效率)

尽可能少操做DOM

5、React的用法

在react当中: 一、基于数据驱动(修改状态数据,react帮助咱们从新渲染视图)完成的组件叫作“受控组件(受数据管控的组件)” 二、基于ref操做DOM实现视图更新,叫作“非受控组件” 真实项目中,建议多使用“受控组件”

VUE:MVVM 数据更改,视图跟着改变,视图更改,数据也跟着改变(双向数据绑定) React:MVC 数据更改视图跟着改变(本来是单向的,可是咱们能够手动设置为双向的)

render(){
  let {text} = this.state;

  return <section className='panel panel-default'>
      <div className='panel-heading'>
          <input type="text" className='form-control' value={text} onChange={ev=>{
              // 在onChange中修改状态信息,实现的是视图改变数据
              this.setState({
                  text:ev.target.value
              })
          }}/>
      </div>
      <div className='panel-body'>
          {text}
      </div>
  </section>
}
复制代码

6、生命周期

所谓生命周期函数(钩子函数)描述一个函数或者组件从建立到销毁的过程,咱们能够在过程当中间,基于钩子函数完成本身的一些操做(例如:在第一次渲染完成作什么,或者在第二次即将从新渲染以前作什么等...)

一、基本流程

【基本流程】 constructor: 建立一个组件 componentWillMount: 第一次渲染以前 render:第一次渲染 componentDidMount: 第一次渲染以后 【修改流程】 当组件的状态数据发生改变(setState)或者传递的属性发生改变(从新调用组件,传递不一样的属性)都会引起render从新执行渲染(渲染也是差别渲染) shouldComponentUpdate 是否容许组件从新渲染 componentWillUpdate 从新渲染以前 render 第二次及之后从新渲染 componentDidUpdate 从新渲染以后

componentWillReceiveProps 父组件把传递给子组件的属性发生改变后触发的钩子函数 属性改变也会改变子组件从新渲染,触发钩子函数

【销毁】 原有的渲染的不消失,之后不能基于数据改变视图 componentWillUnmount 卸载组件以前(通常不用)

index.js:

import React from 'react';
import ReactDOM, {render} from 'react-dom';
import PropTypes from 'prop-types';
import 'bootstrap/dist/css/bootstrap.css'

class A extends React.Component {
    static defaultProps = {}; // 第一个执行,属性设置默认值
    constructor() {
        super();
        console.log('1=constructor');
        this.state = {
            n: 1
        }
    }

    componentWillMount() {
        console.log('3=componentWillMount 第一次渲染前', this.refs.HH);
        // 在这里,若是直接setState修改数据(同步的),会把状态信息改变后,而后render和didMount,若是setState是放到一个异步操做中完成(例如:定时器或者从服务器获取数据),也是先执行render和did
        // 而后再执行这个异步操做修改状态,紧接着走修改的流程(这样和放到didMount中没啥区别),因此咱们通常吧数据请求放到DID中处理
        // 真实项目中的数据绑定,第一次组件渲染,咱们都是绑定的默认属性,第二次才是从服务器获取的数据,有些属性,咱们须要根据数据是否存在,判断显示隐藏
    }

    componentDidMount() {
        console.log('4=componentWillMount 第一次渲染后', this.refs.HH);
        //真实项目中,这个阶段通常作以下处理:
        //  一、控制状态信息更改的操做
        //  二、从服务器获取数据,而后修改状态信息,完成数据绑定
        setInterval(() => {
            this.setState({
                n: this.state.n + 1
            })
        }, 5000)
    }

    shouldComponentUpdate(nextProps, nextState) {
        // this.state.n   更新以前的
        console.log('5=shouldComponentUpdate 函数返回true(容许),false(不容许)');
        // return true

        /*在这个钩子函数中,咱们获取的state不是最新修改的,而是上一次的state的值
         例如:第一次加载完成后,5000ms后,咱们基于setState把n修改成2,可是此处获取的仍是1呢
         可是这个有两个参数:
          nextProps:最新修改的属性
          nextState:最新修改的状态
        */

        if (nextState.n > 3) {
            return true
        } else {
            return false
        }
    }

    componentWillUpdate(nextProps, nextState) {
        // this.state.n  也是更新以前的,也有两个参数存储最新的信息
        console.log('6=componentWillUpdate');
    }

    componentDidUpdate() {
        // this.state.n   更新以后的
        // 先render
        console.log('8=componentWillUpdate');
    }

    render() {
        console.log('2=render');
        return <section ref='HH'>
            {this.state.n}
        </section>
    }
}

ReactDOM.render(<main>
    <A></A>
</main>, root);
复制代码

7、复合组件的传值

父组件传子组件:

基于属性传便可(并且传递是单方向的:只能把信息给儿子,儿子不能直接把信息做为属性传递给父亲) 后期子组件中的信息须要修改: 可让父组件传给子组件的信息发生变化(也就是子组件接收的属性发生变化,子组件会从新渲染 => componentWillReceiveProps钩子函数)

子改父:

相似于这种子改父的操做,咱们须要使用一下技巧: 一、把父组件中一个方法做为属性传递给子组件 二、在子组件中,把基于属性传递进来的方法,在合适的时候执行(相对于在执行父组件中的方法:而这个方法中彻底能够操做父组件的信息)

相关文章
相关标签/搜索