React教程(详细版)-程序员宅基地

技术标签: react.js  框架  javascript  

目录

  • 1、简介

    • 1.1、概念
    • 1.2、原生js痛点
    • 1.3、React特点
  • 2、React初体验

    • 2.1、html中使用react

      • 2.1.1、创建虚拟dom的方式
      • 2.1.2、关于创建的虚拟dom
    • 2.2、JSX语法

  • 3、React面向组件编程

    • 3.1、安装开发者工具(React Developer Tools )
    • 3.2、组件的分类
    • 3.3、组件实例对象的三大属性
  • 4、React中的事件处理

    • 4.1、高阶函数和函数柯里化
  • 5、生命周期函数

    • 5.1、老版的生命周期过程
    • 5.2、新版生命周期函数
  • 6、DOM的Diff算法

  • 7、脚手架

  • 8、消息订阅-发布机制

  • 9、React路由

  • 10、redux

  • 11、react-redux

  • 12、项目打包运行

  • 13、hooks

  • 14、React拓展知识

一、简介(背景)

本文篇幅较多,建议耐心看完,我相信多少会对你有所帮助!
本文参考于尚硅谷 - 天禹老师视频

1.1、概念

它是一个将数据渲染为HTML视图 的js库

1.2、原生js痛点

  • 用dom的API去操作dom,繁琐且效率低
  • 用js直接操作dom,浏览器会进行大量的回流和重绘
  • 原生js没有组件化的编程方案,代码复用性低,哪怕有模块话的概念,但模块化也只能拆解一个个js,对样式和结构也没办法拆解,组件化就相当于3剑客整体拆解,成为一个个的小功能

1.3、React特点

  • 采用组件化模式,声明式编码,提高开发效率和组件复用性
  • 在React Native中可以用react预发进行安卓、ios移动端开发
  • 使用虚拟dom和有些的diffing算法,尽量减少与真实dom的交互,提高性能

二、React初体验

2.1、html中使用react

需求:往div中添加一个h1标签

在这里插入图片描述

代码注解:这里涉及到3个库文件,一个react(核心库),react-dom(用于支持react操作dom的)还有一个babel(将jsx语法转成js语法,因为浏览器只能识别js),还有就是script标签中的type需要写成text/babel,因为script标签中要写jsx的语法,这里再说一点,就是你引入了react-dom库,就可以使用ReactDOM变量了,跟以前学习jquery一样,引入jquery文件就可以使用$和jquery是同样的道理

2.1.1、 创建虚拟dom的方式

①使用原生js的方式去写(一般不用)
在这里插入图片描述

代码注解:使用原生js来创建虚拟dom时,此时script标签的type就不需要写成text/babel,写成原来的text/javascript就可以了,同时也可以删除babel库了,因为不需要它进行转换,浏览器本身就能识别

②使用jsx语法创建(就是最开始的那种方式)

这里可能会有小伙伴会问,为什么不用js来创建dom呢?我看写起来也还行啊,这是因为你还没见过结构嵌套的情况,当需求改为h1标签内再嵌套一个span标签,你怎么办?是不是后面还得再继续套React.createElement(‘span’,{},‘span内容’) ,那如果继续嵌套呢?是不是废了。。。,所以这里就能看出jsx的好处了,其实babel将jsx转换后的代码就相对于用原生js写的那样,只不过这些不用你写,babel帮你转换

2.1.2、 关于创建的虚拟dom

  1. 本质上其实就是一个object对象;
  2. 虚拟dom上的属性比较少,真实dom属性多,因为虚拟dom只在recat内部使用,用不到那么多的属性
  3. 虚拟dom最终会被react转换成真实dom,呈现再页面上

2.2、JSX语法

  • 定义虚拟dom时不要用引号
  • 标签中引入js表达式要用{}
  • 如果在jsx要写行内样式需要使用style={ {coler:red}}形式
  • 样式的类名指定不能写class,要写className;
  • 只有一个根标签
  • 标签必须闭合
  • 标签首字母
    ①若小写字母开头,则会将该标签转为html同名标签,如果没找到,则会报错;
    ②若大写字母开头,则会认为是组件,它就会去找对应的组件,如果没找到,就会报组件未定义的错误;

三、React面向组件编程

3.1 安装开发者工具(React Developer Tools )

这里工具的具体安装方式就不多说了,由两种方式,一种是翻墙,直接在chrome浏览的商城去下载,还有一种方式是在浏览器扩展程序中打开开发者模式,然后导入已下载的插件文件即可

3.2 组件的分类

1. 函数式组件(适用于简单组件)
在这里插入图片描述

2. 类式组件(适用于复杂组件)
在这里插入图片描述

3.3 组件实例对象的三大属性

3.3.1、 state

这里我们用一个小需求来说说state和组件内绑定方法这两个问题,需求:点击文本,改变天气状态

在这里插入图片描述

上述图片中的例子这样的写法并不能实现我们的需求,为什么?因为changeWeather方法中打印的this是undefined,不是该weather组件的实例对象,自然也就无法拿到该实例对象上的state等属性,更加不用说去改变state中的状态了。。。那为什么会这样的?原因就写在图中,那我们要怎么处理才能让该方法拿到该组件的实例对象呢?来,看下面。。

在这里插入图片描述

在构造函数中加一句这个语句就可以了,那这行代码是什么意思呢?
构造函数中的this永远指向该组件的实例对象,所以=右侧意思就是该组件实例对象自身此时还没有该方法,他就会去原型对象上看有没有,显然这里是有的,然后调用bind方法,该方法做两件事,一、创建一个新的函数;二、函数内的this指向bing()括号中传入的,显然这里是组件实例对象;右侧执行完后,将该方法赋值给了实例对象本身的一个方法名(changeWeather),这样实例对象本身就有一个changeWeather方法了,并且内部this就是组件实例对象,所以此时render中点击调用的那个方法,实际上是this实例对象自身的一个changeWeather方法,而不是写在类中的那个原型对象上的changeWeather方法,我们为了不混淆两个重名的方法,我们区分看一下

在这里插入图片描述
好了,接下来我们要做改变状态这件事了,我们要通过react中的内置API(setState方法),不能直接更改state,就像下面这样。
在这里插入图片描述

好了,到现在需求已经满足了,但我们要对其简化。。。
在这里插入图片描述

上述将state和自定义方法直接写在了类中,这样写的意思就是说,给类组件的实例对象添加了一个state属性和自定义方法,而且这里的自定义方法必须写成箭头函数的形式,因为箭头函数内部是没有this指向的,他会去他外部找this,那此时外部的this就是组件实例对象

总结:

  • state是组件实例对象最重要的属性,必须是对象的形式

  • 组件被称为状态机,通过更改state的值来达到更新页面显示(重新渲染组件)

  • 组件render中的this指的是组件实例对象

  • 状态数据不能直接赋值,需要用setState()

  • 组件自定义方法中的this为undefined,怎么解决?

    ①将自定义函数改为表达式+箭头函数的形式(推荐)
    ②在构造器中用bind()强制绑定this

3.3.2、 props

props就是在调用组件的时候在组件中添加属性传到组件内部去使用

简单demo:
在这里插入图片描述
接下来这里我们想对传入的props属性进行一些必传、默认值、类型的校验,所以就需要用到一个prop-types库

下载:npm i prop-types --save
引入:import PropTypes from ‘prop-types’

在这里插入图片描述
构造器问题

构造器仅用于以下两种情况:

  • 通过this.state赋值对象来初始化内部的state
  • 为事件处理函数绑定实例(就是上面的this.changeWeather=this.changeWeather.bind(this))

但是上述的这两个点我们都有简单的方法来实现,state我们可以用state={name:11}这种直接赋值的方式来实现,自定义事件的话可以通过赋值语句+箭头函数的方式来实现,所以一般开发过程中都不写构造器,还有就是如果一定要写构造器,那么构造器是否接受props,是否传递给props,取决于是否要在构造器中通过this访问props

函数组件中的props

在这里插入图片描述

因为函数组件没有组件实例对象,所以其他两个state和refs是没有的,只有props属性可用,直接在()中接受props对象即可,函数内部就可以结构使用props中的值了

总结:

  • 每个组件都会有props属性
  • 组件标签的所有属性都保存在props
  • 组件内部不能改变外部传进来的props属性值

3.3.3 refs属性

  • 字符串形式的ref(这种方式已过时,不推荐使用,因为效率低)

refs是组件实例对象中的属性,它专门用来收集那些打了ref标签的dom元 素,比方说,组件中的input添加了一个ref=“input1”,那么组件实例中的refs就={input1:input(真实dom)},这样就可以通过this.refs.input1拿到input标签dom了,就不需要想原生js那样通过添加属性id,然后通过document.getElementById(“id”)的方式拿

  • 回调函数形式
    在这里插入图片描述

直接让ref属性=一个回调函数,为什么这里说是回调函数呢?因为这个函数是你定义的,但不是你调用的,是react在执行render的时候,看到ref属性后跟的是函数,他就会帮你调用了,然后把当前dom标签当成形参传入,所以上述例子这样写,就相当于把当前节点dom赋值给了this.input1,那这个this指的是谁呢?不难理解,这里是箭头函数,本身没有this指向,所以这个this得看外层的,该函数外层是render函数体内,所以this就是组件实例对象,所以ref={c=>this.input1=c}意思就是给组件实例对象添加一个input1,最后要取对应节点dom也直接从this(组件实例中取)

这里我们再来探讨一个小问题,就是这个ref的回调函数会被执行几次的问题?第一次在页面刚进来执行render渲染的时候,react会把当前节点当成参数赋值给组件实例,当组件更新的时候(状态改变时),它又会执行一次render,这个时候,react官方说明了这点,它会执行两次,第一次是将原先的实例属性清空,传入的是null,第二次再把当前节点传如赋值给组件实例的input1属性,这个在一般开发过程中无关紧要,所以大家知道下有这个情况就可以了,当然它也有解决办法:通过将ref的回调函数定义成类的绑定函数的方式,即ref={this.func},func是定义在类中的方法,func==>{this.input1=c} ,这种方式就可以解决上述执行两次的问题,一般开发中我们写成回调的形式就可以了

  • createRef
    在这里插入图片描述

代码解读:createRef()方法是React中的API,它会返回一个容器,存放被ref标记的节点,但该容器是专人专用的,就是一个容器只能存放一个节点;
当react执行到div中第一行时,发现input节点写了一个ref属性,又发线在上面创建了myRef容器,所以它就会把当前的节点存到组件实例的myRef容器中

注意:如果你只创建了一个ref容器,但多个节点使用了同一个ref容器,则最后的会覆盖掉前面的节点,所以,你通过this.ref容器.current拿到的那个节点是最后一个节点

四、 React中的事件处理

  1. 通过onXxxx属性指定事件处理函数(小驼峰形式)
  2. 通过event.target可以得到发生事件的Dom元素
  3. 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

4.1 高阶函数和函数柯里化

在这里插入图片描述
我们写个用到高阶函数和函数柯里化的例子:

...其余代码省略

saveFormData=(type)=>{  
	return (event)=>{
		this.setState({
			[type]:event.target.value  
		})
	}
}

<form>
	<input onChange={ this.saveFormData('username') } />
	<input onChange={ this.saveFormData('password') } />
	<button>登录</button>
</form>

上面代码的saveFormData函数其实就是高阶函数,因为它返回的值是一个函数,而且这个函数就是通过函数柯里化的方式在调用(先是saveFormData函数接收一个参数type,随后返回函数,然后再接收别的参数,然后最终来处理结果(设置state值))

  • 提问1:那为什么要写成这样呢?我直接在函数saveFormData中同时接收两个参数不行吗?
    答:不行,因为你拿不到event,因为这是react帮你处理的

  • 提问2:那还有没有别的方式来实现,不用柯里化处理方式?
    答:有

//将下面函数的调用方式改为这样就可以了,函数接收方式也改下

saveFormData=(type,value)=>{
	this.setState({
		[type]:value
	})
}
<form>
	<input onChange={ (event)=>{this.saveFormData('username',event.target.value)} } />
	<input onChange={ (event)=>{this.saveFormData('password',event.target.value)} } />
	<button>登录</button>
</form>

五、 生命周期函数

5.1 老版的生命周期过程:
在这里插入图片描述
挂载时:先执行构造器(constructor)=》组件将要挂载(componentWillMount)=》组件挂载渲染(render)=》组件挂载完成(componentDidMount)=》组件销毁(componentWillUnmount)

组件内部状态更新:组件是否应该更新(shouldComponentUpdate)=》组件将要更新(componentWillUpdate)=》组件更新渲染(render)=》组件更新完成(componentDidUpdate)

强制更新:调用this.forceUpdate(),这个api和setState一样都是react自带的,一般这个强制更新很少用,它的执行流程就是比上述的正常更新流程少一步询问是否更新(shouldComponentUpdate)

父组件重新render:调用组件将要接收新props(componentWillReceiveProps)=》组件是否应该更新(shouldComponentUpdate)=》组件将要更新(componentWillUpdate)=》组件更新渲染(render)=》组件更新完成(componentDidUpdate)

注意:上述加粗的函数,只有在父组件状态发生改变了,重新调用render时才会调用子组件的componentWillReceiveProps函数,父组件第一次引用子组件的时时不会调用的

5.2 新版生命周期函数
在这里插入图片描述

新版生命周期函数和旧版的差别:新版即将废弃老的3个钩子(componentWillMount、componentWillReceiveProps、componentWillUpdate),新增了2个钩子(getDerivedStateFromProps、getSnapshotBeforeUpdate)

六、 DOM的Diff算法

虚拟DOM中的key的作用:

当状态中的数据发生改变时,react会根据【新数据】生成【新虚拟DOM】,随后react会进行【新虚拟DOM】和【旧虚拟DOM】的diff算法比较,具体的比较规则如下:

  • 若【旧DOM】中找到了与【新DOM】相同的key,则会进一步判断两者的内容是否相同,如果也一样,则直接使用之前的真实DOM,如果内容不一样,则会生成新的真实DOM,替换掉原先的真实DOM
  • 若【旧DOM】中没找到与【新DOM】相同的key,则直接生成新的真实DOM,然后渲染到页面

用index作为key可能引发的问题

  1. 若对数据进行:逆序添加、逆序删除等破坏顺序的操作时会产生不必要的真实DOM更新,造成效率低下
  2. 如果结构中还包含输入类的dom,会产生错误dom更新,出现界面异常

开发中如何选择key

  1. 最好选中标签的唯一标识id、手机号等
  2. 如果只是简单的展示数据,用index也是可以的

七、 脚手架

使用create-react-app(脚手架工具)创建一个初始化项目

1、下载脚手架工具:npm i -g create-react-app

2、创建引用:create-react-app my-app

3、运行应用:cd my-app(进入应用文件夹),npm start(启动应用)

7.1 React脚手架配置代理

  • 方法一

在package.json中追加如下配置

"proxy":"http://localhost:5000"

说明:

1、优点:配置简单,前端请求资源可以不加任何前缀
2、缺点:不能配置多个代理(如果请求的不同服务器就不行)
3、工作方式:当请求了自身3000端口不存在的资源时,那么会转发给5000端口(优先会匹配自身的资源,如果自己有就不会请求5000端口了)

  • 方法二

1、第一步:创建代理配置文件

在src下创建配置文件:src/setupProxy.js

2、编写代理配置规则
在这里插入图片描述
说明:

1、优点:可以配置多个代理,可以灵活控制请求是否走代理
2、缺点:配置繁琐,前端请求资源时必须加前缀

八、 消息订阅-发布机制

背景:

原先react传递数据基本用的是props,而且只能父组件传给子组件,如果子组件要传数据给父组件,只能先父组件传一个函数给子组件,子组件再调用该方法,把数据作为形参传给父组件,那考虑一个事情,兄弟间组件要如何传递数据呢?这就要引出下面这个消息订阅-发布机制

工具库:PubSubJs

下载:npm install pubsub-js --save

使用:

  1. 先引入:import PubSub from “pubsub-js”
  2. 要接收数据方订阅:PubSub.subscribe('消息名',(data)=>{ console.log(data) })
  3. 传递数据方发布:PubSub.publish('消息名',data)

九、React路由

9.1 相关理解

9.1.1.SPA理解

  • 单页面应用(single page web application SPA)
  • 整个页面只有一个完整的页面(html文件)
  • 点击页面的链接不会刷新页面,只会做页面的局部更新
  • 数据都需要通过ajax请求获取,并在前端异步展示

9.1.2.路由的理解

1、 什么是路由?

  • 一个路由就是一个映射关系
  • key永远为路径,value可能是function或者component

2、 路由分类

  • 后端路由

    a )理解:后端路由的key还是路径,只不过value是上述说的function,这个在学习node和Express的时候应该看到过,如下图
    在这里插入图片描述
    b) 注册路由:router.get(path,function(req,res){…})
    c) 工作过程:当node接收到一个请求时,会根据请求路径去匹配对应的路由,然后调用对应路由中的函数来处理请求,返回响应数据

  • 前端路由

    a) 浏览器端路由,value是对应组件(component),用于展示页面内容
    b) 注册路由:<Route path='/test',component={Test}>
    c) 工作过程:当浏览器path变为/test时,当前路由组件就会变成Test组件

9.2 react-router-dom

9.2.1 理解

  • 它是react的一个插件库
  • 专门用来实现一个SPA单页面应用
  • 基于react的项目基本都用它

9.2.2 常用API

1、内置组件

  • <BrowserRouter>
  • <HashRouter>
  • <Route>
  • <Redirect>
  • <Link>
  • <NavLink>
  • <Switch>

2、知识点

  • 路由的基本使用
    在这里插入图片描述

  • 路由组件和一般组件
    在这里插入图片描述

  • NavLink的使用
    在这里插入图片描述

  • Switch的使用
    在这里插入图片描述

  • 路由的模糊匹配和精准匹配
    在这里插入图片描述

  • Redirect的使用
    在这里插入图片描述

  • 嵌套路由
    在这里插入图片描述

  • 向路由组件传递参数
    在这里插入图片描述

  • 路由跳转的两种模式(push、replace)

默认开启的是push模式,push模式就是说每次的点击跳转改变路径,都是往浏览器历史记录的栈中不断追加一条记录,然后你点回退按钮时,它会指向当前栈顶记录的前一条,replcae模式就是说替换掉当前的那条记录,然后你点回退的时候,就不会显示上次被替换掉的那条记录了,只会显示上上条记录,那要怎么设置为replace模式呢?直接在<Link replace to='XXX'>标签上添加一个replace属性即可

  • 编程式路由导航(不借助link或者navLink这种手动点触发路由跳转)

就是借用history对象的api来操作路由的跳转、前进、后退

在这里插入图片描述

  • withRouter的使用

作用:它就是专门解决在一般组件中想要使用路由组件的那几个API的这个问题的,它接收一个一般组件,然后调用后,该一般组件身上也有了路由组件的history、match等属性

如何使用:
1、先引入import { withRouter} from "react-router-dom"
2、定义一般组件class XX extends ...
3、export default withRouter( XX )

  • BrowserRouter和HashRouter的区别
    在这里插入图片描述

10、redux

10.1 redux理解

10.1.1 redux是什么?

  1. 它是专门做状态管理的js库,不是react插件库
  2. 它可以用在angular、vue、react等项目中,但与react配合用到最多
  3. 作用:集中式管理react应用中多个组件共享的状态

10.1.2 什么情况下需要使用它

  1. 某个组件的状态需要让其他组件也能拿到
  2. 一个组件需要改变另一个组件的状态(通信)
  3. 总体原则:能不用就不用,如果不用比较吃力,就可以使用

redux的工作流程
在这里插入图片描述

11、react-redux

原先redux是独立公司创建的,后来react公司发现开发者都这么喜欢在react项目中使用redux,所以就自己开发了一个react的插件叫react-redux

11.1、react-redux模型图

在这里插入图片描述

11.2、react-redux基本使用

在这里插入图片描述

11.2、纯函数

在这里插入图片描述

11.3、react-redux开发者工具

  1. 打开chrome网上商店,下载开发者工具Redux DevTools
  2. 下载完后右上方的插件图标还是不会亮的,因为它还识别不了你写的redux,所以还需要下载一个库(redux-devtools-extension)
  3. 然后再你的store文件中引入该库文件import {composeWithDevTools} from redux-devtools-extension
  4. 然后再createStore()的第二个参数位置调用composeWithDevTools(),将之前放在这个位置的中间件传到该方法中
    export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))

12、项目打包运行

在react脚手架中通过npm run start 来运行启动项目并打开页面,打包生成静态文件就要用到另一个命令(npm run build),它会生成一个build文件夹,一般这个生成的静态文件都是放到服务器上去运行的,那么问题来了,服务器要怎么搭建呢?

方法一:用node+express可以搭建一个简单的服务器
方法二:需要用到一个库serve,使用前需要先下载npm i serve -S,然后直接在对应文件夹中执行serve即可,比方在这里,当前文件路径是项目根目录,直接serve build即可,就可以开启一个5000端口的服务器了

13、Hooks

13.1、React Hook /Hooks是什么?

1、Hook是React 16.8新推出的新特性/新语法
2、可以让你在函数式组件中使用state或其他特性

13.2、三个常用Hook

1、React.useState()
2、React.useEffect()
3、React.useRef()

13.3、useState

在这里插入图片描述
Demo:

import React,{useState} from 'react';

export default ()=>{

  //useState()中接收的是state的默认值,前面是数组解构,第一个是state变量,第二个是改变state的方法,类似于setState()
  const [count,setCount] =useState( 0 )
  	render(
  		<div>{count}</div>
  		<button onClick={()=>{setCount(count+1)}}>点我+1</button>
  	)
}

这里思考个问题,当你点击按钮+1时,状态改变的时候,整个函数组件就会执行,所以第四行也自然会执行,那它的状态不就又变成0了吗?还能正常+1吗?

答案:是可以正常+1,为什么呢?因为这行代码底层做了处理,当状态改变重新调用整个函数组件时,这句话是会执行,但它不会去覆盖count值,所以count值还是会正常+1

13.4、useEffect
在这里插入图片描述

总结:这个钩子函数相当于类组件三个钩子函数的集合,当你想用做componentDIdMount时,可以在第二个参数中加上[],表示谁都不监听,只会在第一次挂载时调用,这就相当于didMount函数了,如果你想当componentDidUpdate函数用,那么你可以在第二个参数加上你要监听更新的state值,注意是数组,如果你要当componentWillUnmount函数,则在useEffect()接收的第一个函数中返回一个函数,这个返回的函数就相当于willUnMount

13.5、useRef
在这里插入图片描述

14、React扩展知识

14.1、setState的两种写法在这里插入图片描述

Demo:

//这里我们先统一不考虑第二个参数回调

对象式写法:
const {count} =this.state;
this.setState({ count:count+1})    //setState()方法接收一个对象

函数式写法:
this.setState((state,props)=>{    //函数式写法可以接收老的state和props数据
	return {count:1}
})
简写:this.setState(state=>({count+state}))

14.2、lazyload(懒加载)

这里我们要讲的懒加载主要是针对路由组件的懒加载,就是你点击路由导航菜单,加载对应组件的时候懒加载,具体来看下面code。。。

//原先的路由组件引入:
import Demo1 from "./Demo1"
import Demo2 from "./Demo2"

<Route path='/demo1',component={Demo1}/>
<Route path='/demo2',component={Demo2}/>

//现在使用lazyload:
import React,{component,lazy} from "react    // 需要用到react中的lazy函数

// 引入路由组件方式通过调用lazy(),然后接收一个函数的方式,import 引入文件也可以通过函数调用的方式
const Demo1 = lazy(()=>{import('./Demo1')})  
const Demo2 = lazy(()=>{import('./Demo2')})  

//路由配置那边也要改动,用Suspense标签包裹下,再传一个fallback属性,接收一个组件,你可以自定义一个加载过程中的简单组件,再资源没回来之前会显示这个传入的简单加载组件,就是为了再网速慢得情况下,页面不至于白屏,提高用户体验
<Suspense fallback={组件}>
	<Route path='/demo1',component={Demo1}/>
	<Route path='/demo2',component={Demo2}/>
</Suspense>

**注意:**这里引入得加载组件必须通过直接引入的方式import Loading from "./Loading"`

14.3、Fragment标签

在这里插入图片描述

简单一句话概括:这个标签就是用在有时页面结构层级太多,而且有些都是语法要求,实际没意义的结构层级(return()中的根节点就是这个情况),这时你就可以用Fragment标签,当然<></>在一般情况下和Fragment标签作用相同,当时有一点不一样,就是Fragment标签能接收一个key属性,而<></>什么属性都不能接收

14.4、Context

理解:这里说的Context其实就是类组件中实例对象中的一个属性,它和state、props、ref是同一级的;
作用:它可以解决多层组件之间,祖先组件要往后代组件传递数据的情况,不用再一层一层的props传
使用原理: 举个例子,要把父组件中state的值传递给孙子组件,那么在父组件的全局位置创建一个容器对象,然后用这个容器对象的Provider标签包裹父组件,同时传value={state数据},注意,这里的value字段名不能改,只能是value,然后孙子组件可以用下面的两种方式去接收数据

在这里插入图片描述

14.5、PureComponent(纯组件)

在这里插入图片描述

具体的使用:就是原先extends Component=》extends PureComponent 即可

14.6、错误边界

所谓的错误边界就是说,在实际开发过程中,组件复用是很正常的,但你很难避免调用的子组件出现错误(语法错误,或者是因为数据格式不对导致的报错,你不可能兼容到各个位置),如果没有错误边界,当子组件出现问题的时候,整个页面就都会挂掉,所以为了用户体验,让错误不影响整个页面,所以要用这个错误边界,注意:这个错误边界时要在父组件中进行处理的

在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Ronychen/article/details/114669364

智能推荐

西门子HMI SMART 700 IE 设备概况以及WinCC flexible 2008常用配置小记-程序员宅基地

文章浏览阅读1.2w次,点赞3次,收藏32次。——参考自:SIMATIC HMI设备 Smart 700 IE、Smart 1000 IE 操作说明HMI 设备一旦探测到操作员控件被触摸就会立即返回一个反馈。该反馈是独立的,与 PLC 的通讯无关。 因此,其并不指示相关动作是否已真正执行。设计Smart Panel 700 IE是Smart Panel 700的升级版。连接HMI与PC连接组态PC与SMART PANEL有两种连接方式,一种是通过 RS485/422 接口连接,另一种是通过以太网接口连接,后者接线图如下图所示:HM_wincc flexible 2008

设备驱动模型(kobject、kset、ktype)_kobject kset ktype-程序员宅基地

文章浏览阅读570次。转自https://blog.csdn.net/guet_kite/article/details/78368928设备驱动模型概述Linux早期时候,一个驱动对应一个设备,也就对应一个硬件地址,那当有两个一样的设备的时候,就要写两个驱动,显然是不合理的。应该是从Linux2.5开始,就引入了device-bus-driver模型。其中设备驱动模型主要结构分为kset、kobject、kty..._kobject kset ktype

关于换行以及换行属性_nowarp也会换行-程序员宅基地

文章浏览阅读1.9k次。对于CSS的white-space属性,我想大部分人应该和我差不多,最常用的就是nowrap属性,最多用来做超长省略号显示的时候会用到【hiahiahia~】起因是这样的:产品doggie策划了一个元旦活动,活动主页最下边需要显示配置的活动规则,注意,是配置的活动规则,所以,免不了运营小妹要在后台配置一个活动规则,肯定不指望她们能配置html文本的呀,对吧,于是她们配置的是这样的: 1、封垫苏菲房间都是克拉夫; 2、对方萨芬的刷分放大; 3、粉打发打发打发这样色的,于..._nowarp也会换行

BRVAH万能适配器_andriod brvah适配器万能官网-程序员宅基地

文章浏览阅读353次。BRVAH一.简介二.使用一.简介BRVAH是一个强大的RecyclerAdapter框架(什么是RecyclerView?),它能节约开发者大量的开发时间,集成了大部分列表常用需求解决方案。二.使用在使用时,首先要项目的build.gradle导入allprojects { repositories { google() jcenter() ..._andriod brvah适配器万能官网

计算机文化基础作品ppt,计算机文化基础PPT课件-程序员宅基地

文章浏览阅读91次。计算机文化基础PPT课件2019-03-15计算机文化基础PPT课件 第1章http://wenku.baidu.com/view/e7ef8b6925c52cc58bd6be97.html计算机文化基础PPT课件 第2章 Windows 2000操作系统http://wenku.baidu.com/view/e85671f5f61fb7360b4c6594.html计算机文化基础PPT课件 ..._计算机文化基础ppt

获得迭代器最后一个元素_处理迭代器最后一个元素-程序员宅基地

文章浏览阅读3k次。来源python123获得迭代器最后一个元素问题尝试使用 * 迭代器展开运算,返回 range(0, 1000, 4) 的最后一个元素。print([x for x in range(0,1000,4)][-1])输出:996..._处理迭代器最后一个元素

随便推点

第七章 PX4-Pixhawk-Mavlink解析_px4 mavlink 波特率-程序员宅基地

文章浏览阅读5.2k次,点赞3次,收藏25次。第七章 PX4-Mavlink解析首先我们是还是来说一说mavlink吧。Mavlink协议是无人机的一种开源通信协议。可以理解就是按照一定的格式来发送数据。这一章节涉及到了消息的打包发送和接收解析。 首先我们还是找到入口函数然后回到脚本启动中找到mavlink的启动,这个找到应该不难吧,前面几章都有这个。这里有一个需要提一下,很多_px4 mavlink 波特率

Python 中RSA的用法 使用pyOpenssl 生成RSA密钥对, 使用rsa 加解密_import base64 import rsa from openssl.crypto impor-程序员宅基地

文章浏览阅读1.6k次,点赞4次,收藏8次。1. pyOpenSSL 生成RSA密钥对, 效率比较高2. rsa 加解密方法简单3. 代码import rsaimport base64from OpenSSL.crypto import PKeyfrom OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM, FILETYPE_ASN1from OpenSSL.crypto import dum..._import base64 import rsa from openssl.crypto import pkey from openssl.crypto

Android 架构设计(四):组件化?_android 组件化 去除相关组件-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏3次。同系列传送门Android 架构设计(一):设计模式分析_赵星海的博客-程序员宅基地Android 架构设计(二):分包和文件结构_赵星海的博客-程序员宅基地_android 分包结构Android 架构设计(三):技术选型_赵星海的博客-程序员宅基地关于组件化,我这边分三步与大家分享:1定义,2需求,3优劣,4改造步骤(含框架推荐);1、组件化的定义:各个业务模块可单独运行,模块相互联系只可以使用唯一的入口。如图:2、当前项目是否需要采用组件化?首先看项目大小,.._android 组件化 去除相关组件

通过设置偏移 添加RecyclerView分隔线_rv_list.additemdecoration(new recyclerviewdivider距-程序员宅基地

文章浏览阅读701次。添加RecyclerView分隔线_rv_list.additemdecoration(new recyclerviewdivider距离左侧

深入理解计算机系统--计算机系统漫游_深入理解计算机系统 jeancheng-程序员宅基地

文章浏览阅读282次。第一章 计算机系统漫游 计算机系统是由硬件和系统软件组成的。所有计算机系统都是由相似的硬件和软件组成,它们又执行着相似的功能。 以hello程序为例。 1.1信息就是位+上下文 hello程序的生命是从源程序(源文件)开始的。源程序是程序员编写的,hello.c。源程序是 0和1 的比特位,8个一组。ASCII标准来表示文本字符。 这样的文件称为文本文件,所有其他_深入理解计算机系统 jeancheng

python读取json字符串_json数据处理:读取文件中的json字符串,转为python字典-程序员宅基地

文章浏览阅读1.4k次。方法1:读取文件中的json字符串,再用json.loads转为python字典import jsonstr_file = ‘./960x540/config.json‘with open(str_file, ‘r‘) as f:print("Load str file from {}".format(str_file))str1 = f.read()r = json.loads(str1)pri..._python 提取json元素 获取两个字段的值组成字典