https://www.bilibili.com/video/BV1eE411W7WT?p=7
react把DOM
抽象成为一个JS对象,通过这个JS对象来描述相关的页面中的真实DOM
,通过这个JS对象来实时的更新真实DOM
。这里的JS对象也就是虚拟DOM
。
react通过Diff算法
来保证当页面的DOM
更新的时候,不第一时间去更新真实DOM
,而是去更新虚拟DOM
。(因为页面每操作一个真实dom的时间相对比较长的,这里先更新虚拟DOM
来,然后最后统一来更新真实DOM
,大大地提高效率。)
2013年开始
react是JavaScript第三方库文件,我们需要开发的话,只需要在页面中引用react相关的文件就可以完成。
必须要映入三个文件:
npm i react --save
npm i react-dom --save
npm i babel-standalone --save
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hellotitle>
<script src="./node_modules/react/umd/react.development.js">script>
<script src="./node_modules/react-dom/umd/react-dom.development.js">script>
<script src="./node_modules/babel-standalone/babel.min.js">script>
head>
<body>
<div id="app">div>
<script type="text/babel">//一定要用这个"text/babel"否则不能编译jsx语法
let mydom=<h1>你好世界</h1>;
ReactDOM.render(mydom,document.getElementById("app"))
script>
body>
html>
create-react-app 是来自于 Facebook,通过该命令我们无需配置就能快速构建 React 开发环境。
create-react-app 自动创建的项目是基于 Webpack + ES6 。
执行以下命令创建项目:(脚手架)
npm install -g create-react-app
create-react-app my-app
cd my-app/
npm start
相当于使用插值表达式
需要用一个父元素包裹(否则报错):
最终渲染出来的页面是:
文本一
文本二
如果想在jsx中使用表达式,那么我们就需要把表达式放入一对{ }
中。(插值表达式)
最终渲染出来的页面是:
你好啊
2333
2334
姓名是小明-----年龄是12
三元运算符格式:判断表达式?真即执行:假即执行
最终渲染出来的页面是:
当前手机价格是4999----很贵
最终渲染出来的页面是:
新闻列表1
新闻列表2
新闻列表3
新闻列表4
新闻列表5
新闻列表6
最终渲染出来的页面是:
去百度
style属性可以一直使用对象来设值,不一定使用字符串。
let modStyle = {
color: 'red', backgroundColor: 'pink'
}
let mydom =
修改我的内联样式
;
//注意jsx中不能出现class这个属性,因为class是js的关键字
ReactDOM.render(mydom, document.getElementById("app"))
注意:不能使用class,因为class是js的关键字
在render()
方法中直接传入模板数组来进行渲染,比如:
render([<p key="0">哈哈哈</p>,<p key="1">呵呵呵</p>,<p key="3">嘻嘻嘻</p>],document.getElementById("app"))
react会在render()
函数中根据key
值自动进行渲染。
//react列表渲染 map()
let arr =['吃饭','睡觉','打豆豆'];
let mydom =arr.map((item,index)=>{
//key必须是独一无二的
return (//要换行的话,一定要在return后面加上小括号
<p key={
index}>{
item}</p>
)
})
ReactDOM.render(mydom, document.getElementById("app"))
let arr = ['吃饭', '睡觉', '打豆豆'];
let fun=function () {
let newarr = [];
for (let index in arr) {
newarr.push(<p key={
index}>{
arr[index]}</p>)
}
return newarr
}
ReactDOM.render(fun(), document.getElementById("app"))
let arr = ['吃饭', '睡觉', '打豆豆'];
let index = -1;
let fun = function () {
let mydom = arr.map((v, i) => {
return (<p style={
{
color:i==index?'red':''}} key={
i} onClick={
() => {
index = i;render();
}}>{
v}</p>)
})
return mydom
}
function render(){
ReactDOM.render(fun(), document.getElementById("app"))
}
render()//初次跑一次程序渲染,才能出现内容,才可以有点击事件
var obj={
name:"小明",
age:18
}
console.log(obj.name)//小明
console.log(obj["age"])//18
//通过点的方式会方便很多
//但是要注意:如果key是一个变量的话,就不能使用点这种方式来取值。
console.log(Object.keys(obj))
//返回一个数组类型的数据,得到对象中的所有键(key)
//["name","age"]
console.log(Object.values(obj))
//返回一个数组类型的数据,得到对象中所有属性的值(value)
//["小明",18]
先把对象通过Object.keys()
方法以数组的形式返回该对象的所有键,然后再通过obj[key]
的方法访问对象中单个属性的值。
let obj = {
name: "小明", age: 18, sex: "男"
}
let mydom = <div>
{
Object.keys(obj).map((key, index) => {
return <p key={
index}>{
obj[key]}</p>
})
}
</div>
ReactDOM.render(mydom, document.getElementById("app"))
高耦合就是说逻辑紧密的内容放在一个组件中
低内聚就是说不同组件的依赖关系尽量弱化,每个组件能尽可能的独立起来
1.构建的方式
2.组件的属性
3.生命周期
传统的组件有几个明显的特点,1.简单的封装 2.简单的生命周期的呈现 3.明显的数据流动
当一个项目比较复杂的时候,传统的组件化根本不能很好的把结构样式和行为结合,让项目很难维护。
1.属性props
2.状态state
3.生命周期
通过组件可以把页面中的ui部分切分成独立、高复用性的部分,让每个开发者更加专注于一个个独立的部分。
组件就是用实现页面局部功能的代码集合,简化页面复杂程度,提高运行效率。
最简化就是当前程序都是使用组件完成的, 那么就是一个组件化的应用。
//无状态组件的创建方式:
function Mycom(){
return (
<div>我是一个无状态组件</div>
)
}
let com=<Mycom/>
ReactDOM.render(com,document.getElementById('app'));
//父子组件:
//子组件
function MycomA(){
return (
<div>我是第一组件</div>
)
}
function MycomB(){
return (
<div>我是第二组件</div>
)
}
function MycomC(){
return (
<div>我是第三组件</div>
)
}
//父组件调用
function Com(){
return (
<div>
<MycomA/>
<MycomB/>
<MycomC/>
</div>
)
}
ReactDOM.render(<Com/>,document.getElementById('app'));
//创建类组件 组件名首字母大写
class MyCom extends React.Component {
render(){
return (
<div>类组件</div>
)
}
}
let com=<MyCom/>
ReactDOM.render(com,document.getElementById('app'));
react
类组件的构造方法 constructor():constructor(props){
super(props);
this.state = {
}
}
constructor
必须用super()
初始化this
,可以绑定事件到this
如果你在constructor
中要使用this.props
,就必须给super
加参数,super(props)
;
constructor(){
super();
this.state = {
xxx:this.props.xxx//构造函数里面用到了props
};
}//这里如果在construct()和super()中不传入props参数,则会报错
//因为这里使用super()是重写了父类的构造函数(父类的构造函数本来是super(props,context))
无论有没有constructor()
,重写的构造函数中参数有没有props
,render()
中都可以使用this.props
, 默认自带
如果组件没有声明constructor
,react
会默认添加一个空的constructor
。
class News extends React.Component {
render() {
return (
<div>
new组件:{
this.props.text}
<p>{
this.state.text}</p>
</div>
)
}
}
//如果在继承时,子类中如果没有声明constructor,js会自动生成添加constructor并且调用父类的构造函数
//这里是父类的构造函数是super(props,context),并不是super()如果写super()则是不完全使用父类构造函数方法。
ES6
采用的是先创建父类的实例this
(故要先调用 super( )
方法),完后再用子类的构造函数修改this
constructor( )
-----super( )的基本含义constructor( )——构造方法
这是ES6对类的默认方法,通过 new 命令生成对象实例时自动调用该方法。
并且,该方法是类中必须有的,如果没有显示定义,则会默认添加空的constructor( )方法。
super( ) ——继承
在class方法中,继承是使用 extends 关键字来实现的。
子类必须在 constructor( )调用 super( )方法,否则新建实例时会报错。
(如果子类没有显示定义构造方法,js则会默认加上构造方法并且里面用super自动调用父类的构造方法)
即:
class son extends father{
constructor(){
super()
}
}
如果父类构造方法里面含参数,子类没有显示定义构造方法,js也会默认向子类构造方法中加上参数调用父类的构造方法,例如:
class son extends father{
constructor(name,age){
super(name,age)
}
}
报错的原因是:子类是没有自己的 this 对象的,它只能继承自父类的 this 对象,
然后对其进行加工,而super( )就是将父类中的this对象继承给子类的。
没有 super,子类就得不到 this 对象。
下面是子类显示定义了构造方法,但是并没有向子类构造方法传入父类构造方法本应该传入的形参:
class father {
constructor(name, age) {
this.name = name
this.age = age
}
pick() {
console.log(`年龄:${
this.name}`, `年龄:${
this.age}`)
}
}
class son extends father {
//显示定义了构造方法,但是没有向其中传入父类该有的形参
constructor(name){
//这里我们只传入第一个参数
super(name)
}
pull() {
console.log("jhhh ")
}
}
Father = new father("baba", 40)
Father.pick()//年龄:baba 年龄:40
Son = new son("erzi", 20)
Son.pick()//年龄:erzi 年龄:undefined
//可以看到此时子类虽然使用super继承使用了父类的构造方法,但是只会使用了父类的一个形参
class father {
constructor(name, age) {
this.name = name
this.age = age
}
pick() {
console.log(`年龄:${
this.name}`, `年龄:${
this.age}`)
}
}
class son extends father {
//此时子类直接继承父类,并没有显示定义构造方法
pull() {
console.log("jhhh ")
}
}
Father = new father("baba", 40)
Father.pick()//年龄:baba 年龄:40
Son = new son("erzi", 20)
Son.pick()//年龄:erzi 年龄:20
//此时我们可以知道如果子类没有显示定义构造方法,
//则会默认补上父类的构造方法,而且构造方法的参数和父类都是一致的。
总结:通过这个我们知道如果在react类组件中写出构造函数而且需要在构造函数中使用props属性,必须补上第一个形参作为补位,才能使用得到props
的值。
而这里需要注意的是:react类组件在render()
函数中无论构造函数有没有传入props形参,render()
函数都可以使用到this.props
的值
类组件需要注意js内置事件回调函数的this指向问题。
1. 类组件有自己的状态
2. 继承React.Component-会有生命周期和this
3. 内部需要一个render函数(类组件会默认调用render方法,但不会默认添加,需要手动填写render函数,并return一个能渲染的值。)
4. 类组件的基本架构
5. constructor里边添加自己的属性和状态、方法
a. 写了constructor就要写super
b. 如果c里边没内容只有super,name可以不写
6. 添加状态this.state = {
}; es7写法state = {
}。非双向绑定
7. setState接收对象的情况、批量更新
8. setState接收函数的情况、state与penddingState
9. class里方法的写法
a. 方法里边this的指向undefined的情况
class Person {
fn(){
console.log(this);
}
}
var person = new Person();
var fn1 = person.fn;(这里是将值赋给fn1)
fn1(); //undefined(fn1()当前的指向位置this指向undefined)
b. bind改变this指向
c. 箭头函数继承this指向
d. 匿名函数传参
10. TodoList实战
11. 类组件注意:
注意绑定事件时,"on"后边事件名的首字母大写,如"change"要写成"Change"注意回调函数内部this的指向默认为undefined,要改变this指向
不能直接改变state的值、需要用函数setState来修改state的值
类组件内部没有render函数报错:
因为看到class组件会默认调用render方法
如果看到函数组件,会自动在函数内部添加一个render方法,把函数的return返回值放到render中运行。
所以类组件内部必须有render函数,并return返回一个可渲染的值。不会进行自动添加。
this
是基于函数的执行环境(也就是上下文)绑定的,React组件生命周期函数中this
的上下文就是组件实例。(而js
的变量是通过词法作用域来绑定的)
你必须谨慎对待 JSX
回调函数中的this
,类的自定义方法默认是不会绑定 this
的。首先调用 constructor()
函数, this.state
的this
上下文就是该实例对象;同理,render()
函数中this
也是该实例。
在浏览器中回调函数中的this默认是指向window
的,因为本质上是在函数内callback
,并没有.前
的对象调用,在**nodejs
中的回调函数中的this默认是undefined
**。(回调函数可以参看我之前的总结)
class Bar extends React.Component {
constructor (){
super();
this.state = {
value: 'react'
}
}
changeValue (){
console.log(this) // undefined
}
render (){
console.log(this) // 该组件实例
return (
<div>
<p>{
this.state.value}</p>
<button onClick={
this.changeValue}>click me !</button>
</div>
)
}
}
当我们直接绑定this.changeValue
调用时,会发现他的this
是undefined
;你应该为和这个方法绑定this
。
解决方式:
①:使用 bind()
函数改变this
的上下文(这里只能用bind,不能用call和apply,因为call和apply会立即执行,而bind不会)
call,apply,bind的用法以及区别
这里还是举个栗子来看一下区别:
var obj = {
message: 'My name is: '
}
function getName(firstName, lastName) {
console.log(this.message + firstName + ' ' + lastName)
}
getName.bind(obj, ['Dot', 'Dolby'])//不会执行打印函数,而是返回一个改变了执行上下文this指向之后的函数
getName.bind(obj, ['Dot', 'Dolby'])()// My name is: Dot Dolby
getName.apply(obj, ['Dot', 'Dolby'])// My name is: Dot Dolby
getName.call(obj, 'Dot', 'Dolby')// My name is: Dot Dolby
在这里就可以使用bind来改变回调函数上下文this的指向,并不需要让它马上执行
class Bar extends React.Component {
constructor (){
super();
this.state = {
value:'react'
}
}
changeValue (e){
console.log(e) // 默认event
this.setState({
value:`react ${
parseInt(Math.random()*100)}`
})
}
render (){
return (
<div>
<p>{
this.state.value}</p>
<button onClick={
this.changeValue.bind(this)}>click me !</button>
</div>
)
}
}
也可以在constructor()
中:this.changeValue = this.changeValue.bind(this)
②:es6
的箭头函数
利用箭头函数将函数的this
绑定到其定义时所在的上下文
<div>
<p>{
this.state.value}</p>
<button onClick={
(event) => this.changeValue(event)}>click me !</button>
</div>
或者
changeValue = (e) => {
console.log(e) // 默认event
this.setState({
value:`react ${
parseInt(Math.random()*100)}`
})
}
1.props
是react
中一个重要的属性,是组件对外的接口,我们使用props
就可以从组件的外部向组件的内部进行数据的传递。
2.也可以完成父组件给子组件的数据传递。
3.注意:无论是无状态组件还是类组件,我们都不能修改自身的props
,因为react是单向的数据流。
//使用Props
function Com(props){
return (
<div>我是一个无状态组件-----外部传递的数据是:{
props.text}</div>
)
}
ReactDOM.render(<Com text="我是传递给com的props的数据"/>, document.getElementById('app'));
页面上渲染出的效果:我是一个无状态组件-----外部传递的数据是:我是传递给com的props的数据。
在react的无状态组件中使用props属性,向外部父组件暴露传递值得接口。
1.在子组件中用参数传入props
。
2.在返回的jsx语法中使用插值表达式{props.属性名}
来使用。
3.在外部直接在组件标签内使用属性名="xxxx"
,来传递值。
4.如果要在标签内的属性设置动态的变量也是需要用插值表达式:属性名={定义的变量名}
function Com(props){
return (
<div>我是一个无状态组件-----外部传递的数据是:{
props.text}</div>
)
}
let value="我是变量"
ReactDOM.render(<Com text={
value} />, document.getElementById('app'));
页面中渲染出的效果:我是一个无状态组件-----外部传递的数据是:我是变量。
5.如果我们需要传递多个props属性进入组件中,可以**使用ES6中的扩展运算符{...obj}
**直接写入标签。用法如下:
正常的传入多个props属性用法:
function Com(props){
return (
<div>我是一个无状态组件-----外部传递的数据是:{
props.text}---{
props.num}</div>
)
}
let value="我是变量"
ReactDOM.render(<Com text={
value} num="111"/>, document.getElementById('app'));
页面渲染出的效果:我是一个无状态组件-----外部传递的数据是:我是变量—111
使用ES6
扩展运算符{...obj}
传入标签的用法:
function Com(props) {
return (
<div>我是一个无状态组件-----外部传递的数据是:{
props.text}---{
props.num}</div>
)
}
let obj = {
text: "我是文本值",
num: "222"
}
ReactDOM.render(<Com {
...obj} />, document.getElementById('app'));
页面渲染出的效果:我是一个无状态组件-----外部传递的数据是:我是文本值—222
//类组件使用props
class Com extends React.Component {
render() {
return (
<div>
我是类组件---{
this.props.name}---{
this.props.num}
</div>
)
}
}
ReactDOM.render(<Com name="name的数据" num="num的数据"/>, document.getElementById('app'));
//页面渲染出的效果:我是类组件---name的数据---num的数据
在组件继承的React.Component
类中就定义了props属性
直接使用this.props.属性名
来使用。
同理如果传入多个props属性值
也可以使用ES6的扩展运算符{...obj}
来像标签中传入多个属性值:
//使用es6扩展运算符传入props属性值:{...obj}(插值表达式大括号+扩展运算符)
class Com extends React.Component {
render() {
return (
<div>
我是类组件---{
this.props.name}---{
this.props.num}
</div>
)
}
}
let obj = {
name: 'name的数据',
num: 'num的数据'
}
ReactDOM.render(<Com {
...obj} />, document.getElementById('app'));
//页面渲染出的效果:我是类组件---name的数据---num的数据
//无状态组件的props的验证与默认值
function Com(props) {
return (
<div> 我是无状态组件---{
props.name}</div>
)
}
Com.defaultProps = {
name: '我是name的默认值' }//初始化defaultProps属性中的name
ReactDOM.render(<Com />, document.getElementById('app'));
//我是无状态组件---我是name的默认值
//此时如果在 标签内对name属性进行赋值,则会覆盖defaultProps中name的值
ReactDOM.render(<Com name="我是name的数据" />, document.getElementById('app'));
//我是无状态组件---我是name的数据
使用PropTypes进行类型检查
//无状态组件的props类型验证
//1.引用prop-types库 npm i -S prop-types
//注意需要引入的是prop-types.js文件,而不是上线版的prop-types.min.js文件
function Com(props) {
return (
<div> 我是无状态组件---{
props.name}---{
props.age}</div>
)
}
Com.propTypes = {
name: PropTypes.number,//验证name这个props传递进来的数据必须是number类型
age: PropTypes.number.isRequired
}
// let num = "333"
let num = 222
ReactDOM.render(<Com name={
num} age={
num} />, document.getElementById('app'));
//当num是字符串的时候,页面依然会渲染出来,但是控制台会报错
//当num是数字型的时候,就能完美运行。
// 类组件组件的props的验证与默认值
class Com extends React.Component {
render() {
return (
<div>我是类组件 ---{
this.props.name}</div>
)
}
}
//props默认值设置
Com.defaultProps={
name:'name的默认值'
}
//propTypes的对props的验证(方法与无状态组件一致)
Com.propTypes = {
name: PropTypes.number,//验证name这个props传递进来的数据必须是number类型
}
ReactDOM.render(<Com />, document.getElementById('app'));
//我是类组件 ---name的默认值
在类组件中还可以在组件类中直接使用static defaultProps
来设置默认值:
class Com extends React.Component {
static defaultProps={
name:'name的默认值'
}
render() {
return (
<div>我是类组件 ---{
this.props.name}</div>
)
}
}
ReactDOM.render(<Com />, document.getElementById('app'));
//我是类组件 ---name的默认值
state
状态的介绍state
和props
的区别:
1.state
是组件内部可变的变量。
2.props
对于当前组件来说,它是只读的,如果我们想修改props
中的数据,那么我们需要修改父组件中的状态变量
,然后传递给props
,达成父传子通信的目的。
props
:是组件对外的接口,组件内可以引用其他组件,组件之间的引用就形成了一个树状的结构,如果子组件需要使用父组件的数据,父组件就可以通过子组件中的props
来进行数据传递。(所以说,这个props
也就是组件通信中的父传子的作用)
state
:是组件对内的接口,组件除了父传子通信之外,他自身也需要管理的数据,这个对内管理数据的属性就是state
。(类似于Vue
中的data
属性,这里也有个概念,react
也有对应的响应式和数据绑定原理。)
react
中我们只关心的是数据,当数据改变的时候页面就会自动的发生改变。
状态等同于页面中的数据,状态/数据改变了—页面中对应的数据绑定内容,就会被react
自动的进行改变。(这里的数据就是模板中的数据,这里的状态是指**js
中的变量来修饰数据的状态**)
声明式渲染:一切数据改变操作不用我们关心,只需要我们声明好数据,react自动的对于数据进行相应的改变。
注意:如果要使用状态,那么不能使用无状态的函数组件。
state
的使用在es6中不管子类写不写constructor,都会在new的实例上补上**constructor方法里面用super()**执行父类的构造函数。
(相当于默认子类构造函数就是父类的构造函数)
class Employee{
//父类
constructor(name,position){
//定义构造方法,名字固定
this.name=name
this.position=position
}
}
class Manager extends Employee{
//子类
constructor(name,position){
//可不写子类构造函数,不写就是默认执行父类构造函数
super(name,position)//调用父类的构造函数
}
}
如果想要子类重写父类的构造函数只需要自己写一个constructor方法并且向里面传入需要的参数自定义属性即可。如下:
class Employee{
//父类
constructor(name,position){
//定义构造方法,名字固定
this.name=name
this.position=position
}
}
class Manager extends Employee{
//子类
constructor(name,position,dept){
//重写构造函数,传入其他多的参数
super(name,position)//调用父类的构造函数
this.dept=dept//子类自定义新增属性
}
}
现在我们在来使用状态state
:
// 状态组件:
class Com extends React.Component {
//在es6中不管子类写不写constructor,都会在new的实例上补上constructor方法里面用super()执行父类的构造函数
//(相当于默认子类构造函数就是父类的构造函数)
//如果想要子类重写父类的构造函数只需要自己写一个constructor方法并且向里面传入需要的参数即可
constructor(props) {
super(props)
this.state = {
name: '嘻嘻'
}
}
render() {
//this.setState({key:newValue}) 是异步的,调用react会自动地触发render()进行数据的渲染
return (<div>
<button onClick={
() => {
this.setState({
name:'hhh'})}}>点我改变state的数据</button>
<div>我是的state的值{
this.state.name}</div>
</div>
)
}
}
ReactDOM.render(<Com />, document.getElementById('app'));
this.setState({key:newValue})
是异步的,调用react会自动地**触发render
**进行数据的渲染。(这个异步还是得看情况,在react组件生命周期或react合成事件中是异步的;在setTimeout或原生dom事件中是同步的;)
1.可以在子类的构造函数中使用this.state={key:oldValue}
来使用,比如上面这种情况
2.也可以不把state
放在子类的构造方法中,也就是不用像上面一样重写子类的构造方法,直接在子类的原型中使用state
,如下:
class Com extends React.Component {
state = {
name: '嘻嘻'
}
render() {
return (<div>
<button onClick={
() => {
this.setState({
name:'hhh'})}}>点我改变state的数据</button>
<div>我是的state的值{
this.state.name}</div>
</div>
)
}
}
ReactDOM.render(<Com />, document.getElementById('app'));
ref
区别于state
:ref
是对组件中的dom节点进行标记,在第一次执行render
函数进行渲染页面的时候就会将使用ref
属性的dom节点进行标记,然后可以通过ref
进行查询标记的dom节点,便于操作。(可以管理操作所有的dom节点和子组件)
如果ref
作用在组件上,对组件进行实例化,可以操纵组件,调用组件内部封装的一些函数。但是注意的是,函数组件不可以使用ref,因为函数组件没有实例。
state
是状态组件中管理自身组件状态的对象。(只负责自己)
ref
的介绍:react
当中提供了一个ref
属性(不能在无状态组件中来进行使用,因为无状态组件没有实例)
refs
表示当前组件的真正实例的引用,他返回绑定当前属性的元素。
作用:标识组件内部的元素—方便我们查找。
ref
对逻辑进行处理,需要优先考虑state
,使用ref
过多会到时候组件耦合度高,不利于维护。ref
的使用:react
给我们三种方式进行ref
的使用:
React.createRef()
(react16.3
新提供的一种方式)ref
属性赋值字符串的形式:(这里也可以通过dom查询来获取值)class Com extends React.Component {
fun() {
console.log(document.querySelectorAll('input')[0].value);//打印输入的值
console.log(this.refs.demoInput.value);//打印输入的值
}
render() {
return (
<div>
我是类组件
<input type="text" ref="demoInput" placeholder="请输入" />
<button onClick={
this.fun.bind(this)}>点我得到输入框的值</button>
</div>)
}
}
ReactDOM.render(<Com />, document.getElementById('app'))
就是在dom节点上或者组件上挂载函数,函数的形参是当前dom节点,它实现的效果和字符串的方式是一样的,都是获取当前dom元素
的引用。
class Com extends React.Component {
fun() {
console.log(this.dom.value)
}
render() {
return (
<div>
我是类组件
<input type="text" ref={
(dom)=>{
this.dom=dom}} placeholder="请输入" />
<button onClick={
this.fun.bind(this)}>点我得到输入框的值</button>
</div>)
}
}
ReactDOM.render(<Com />, document.getElementById('app'))
这里的ref={(dom)=>{this.varDom=dom}}
是指把当前这个标识的dom元素
用一个varDom这个变量属性来暂时保存,再来间接使用这个标识的dom元素
。
(这个ref
的回调函数是在第一次render()
渲染的时候触发执行)
React.createRef()
然后用里面的current来取值这里和上面的回调函数的方式差不多,也是把创建的ref标识值赋给一个变量,通过ref属性挂载在到当前dom元素上,使用React.createRef()
的current
属性来拿到这个节点。
class Com extends React.Component {
fun() {
console.log(this.Ref.current.value)
}
Ref=React.createRef()
render() {
return (
<div>
我是类组件
<input type="text" ref={
this.Ref} placeholder="请输入" />
<button onClick={
this.fun.bind(this)}>点我得到输入框的值</button>
</div>)
}
}
ReactDOM.render(<Com />, document.getElementById('app'))
当第一次执行render函数渲染页面的的时候就会执行React.createRef()
,然后把返回值给当前储存标识ref
的变量Ref
,最后就可以使用Ref
(执行了React.createRef()
的返回值临时赋给了Ref
)里面的current
属性取出标识的当前dom元素。
react
绑定事件使用的是小驼峰命名法,在绑定回调函数的时候不能加小括号----->因为加了()
会导致回调函数立即执行。(这里绑定事件是需要回调函数触发执行)
bind
方法原地修改this指向
bind
不能使用call
和apply
(因为只有bind
方法才不会被立即执行,返回修改this
指向之后的函数)constructor()
中提前使用bind
修改this
指向class Com extends React.Component {
constructor(props) {
super(props)
this.func = this.func.bind(this)
}
funa() {
console.log(this);
}
funb = () => {
console.log(this);
}
func() {
console.log(this);
}
fund() {
console.log(this);
}
render() {
return (
<div>
<button onClick={
this.funa.bind(this)}>bind原地修改this</button>
<button onClick={
this.funb}>箭头函数修改</button>
<button onClick={
this.func}>在构造函数提前bind修改</button>
<button onClick={
() => this.fund()/*箭头函数里面的函数需要立即执行*/}>事件调用方式使用箭头函数</button>
</div>)
}
}
ReactDOM.render(<Com />, document.getElementById('app'))
//以上方式点击按钮都可以打印出this指向Com
class Com extends React.Component {
fune = (parameter) => {
console.log(parameter);
}
render() {
return (
<div>
<button onClick={
this.fune("xxx")/*这种方式肯定不行,因为函数会立即执行*/}>点我进行实参传递</button>
<button onClick={
this.fune.bind(this,"hhh")/*这里需要使用bind传参,返回的的函数不会立即执行*/}>点我进行实参传递</button>
<button onClick={
()=>this.fune("jjj")/*这是使用函数嵌套的形式让外面的函数不立即执行,里面的函数可传参立即执行*/}>点我进行实参传递</button>
</div>)
}
}
ReactDOM.render(<Com />, document.getElementById('app'))
这个event对象是点击事件,执行回调函数时浏览器进行传入的event对象实参,我们需要在写回调函数时接受这个参数。
class Com extends React.Component {
funf = (parameter1,parameter2) => {
console.log(parameter1);
console.log(parameter2);
}
fung = (p) => {
console.log(p);
}
render() {
return (
<div>
<button onClick={
(event) => this.funf("jjj",event)/*函数嵌套,设置一个形参,让发送点击事件的时候触发回调传入event实参对象*/}>点我进行event对象传递</button>
<button onClick={
this.funf.bind(this,"xxx")/*会传递一个实参到funf中,funf还需要一个参数没有传,也就是点击事件时触发执行回调会传入的event*/}>点我进行event对象传递</button>
<button onClick={
this.fung.bind(this)/*也可以在函数fung中设置一个形参,但是自己主动不设置实参,让发送点击事件的时候触发回调传入event实参对象*/}>点我进行event对象传递传递</button>
</div>)
}
}
ReactDOM.render(<Com />, document.getElementById('app'))
//点击前两个按钮都会打印出event对象
//点击最后一个按钮也可以直接打印出event对象
条件渲染是什么?
根据状态的变化只渲染其中的一部分。
jsx
模板中不允许有if
)class Com extends React.Component{
state={
bool:true
}
fun=()=>{
this.setState({
bool:!this.state.bool
})
}
render(){
if(this.state.bool){
text='你好'
}else{
text='你坏'
}
return(
<div>
<button onClick={
this.fun}>点我修改下面内容</button>
{
text}
</div>
)
}
}
class Com extends React.Component{
state={
bool:true
}
fun=()=>{
this.setState({
bool:!this.state.bool
})
}
render(){
return(
<div>
<button onClick={
this.fun}>点我修改下面内容</button>
{
this.state.bool?'哈哈哈':'呵呵呵'}
</div>
)
}
}
状态提升:多个组件需要反映相同的数据变化。把这些数据提升到离他们最近的一个父组件中,这个父组件改变了这些数据之后,再通过props
分发给子组件。
使用场景:多个子组件需要利用到对方状态的情况下,那么这个时候就需要使用到状态提升。
class ChildCom1 extends React.Component {
render() {
return (
<div>
我是第一个组件{
this.props.text}
</div>)
}
}
class ChildCom2 extends React.Component {
render() {
return (
<div>
我是第二个组件{
this.props.text}
</div>)
}
}
class FatherCom extends React.Component {
state = {
context: '我是共用的数据'
}
fun() {
this.setState({
context: '改变了的数据'
})
}
render() {
//把两个子组件都需要用到的状态放在这个父组件中
return (
<div>
我是第父组件组件
<ChildCom1 text={
this.state.context} />
<ChildCom2 text={
this.state.context} />
<button onClick={
this.fun.bind(this)}>点我改变子组件类容</button>
</div>)
}
}
ReactDOM.render(<FatherCom />, document.getElementById('app'))
组件的生命周期可分成三个状态:
生命周期的方法有:
组件发生更新的生命周期,又分为两个部分,props
和states
:
记住:组件第一次存在dom中函数不会被执行,如果已经存在于dom中,函数才会被执行
需要在更新this.setState
的前后进行触发:
会先后触发shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate。
会先后触发componentWillReceiveProps、shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate
state
是一致的