B站尚硅谷React入门教程
视频链接:React全家桶(技术栈)
第1章:React入门
1.1. React简介
1.1.1 官网
英文官网: https://reactjs.org/
中文官网: https://react.docschina.org/
1.1.2 介绍描述
用于动态构建用户界面的 JavaScript 库(只关注于视图)
由Facebook开源
1.1.3 React的特点
声明式编码
组件化编码
React Native 编写原生应用
高效(优秀的Diffing算法)
1.1.4 React高效的原因
使用虚拟(virtual)DOM, 不总是直接操作页面真实DOM。
DOM Diffing算法, 最小化页面重绘。
1.2 React的基本使用
1.2.1 效果
1.2.2 相关js库
react.js:React核心库。
react-dom.js:提供操作DOM的react扩展库。
babel.min.js:解析JSX语法代码转为JS代码的库
1.2.3 创建虚拟DOM的两种方式
纯JS方式(一般不用)
JSX方式
1.2.4 虚拟DOM与真实DOM
- React提供了一些API来创建一种 “特别” 的一般js对象
const VDOM = React.createElement('xx',{id:'xx'},'xx')
- 上面创建的就是一个简单的虚拟DOM对象
虚拟DOM对象最终都会被React转换为真实的DOM
我们编码时基本只需要操作react的虚拟DOM相关数据,react会转换为真实DOM变化而更新界。
1.3 React JSX
1.3.1 效果
1.3.2 JSX
全称: JavaScript XML
react定义的一种类似于XML的JS扩展语法: JS +XML本质是React.createElement(component, props, …children)`方法的语法糖
作用: 用来简化创建虚拟DOM
写法:var ele = <h1>Hello JSX!</h1>
注意1:它不是字符串, 也不是HTML/XML标签
注意2:它最终产生的就是一个JS对象
标签名任意: HTML标签或其它标签
标签属性任意: HTML标签属性或其它
基本语法规则
遇到 <开头的代码, 以标签的语法解析:html同名标签转换为html同名元素, 其它标签需要特别解析
遇到以 { 开头的代码,以JS语法解析: 标签中的js表达式必须用{ }包含
- babel.js的作用
浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行
只要用了JSX,都要加上type=“text/babel”, 声明需要babel来处理
1.3.3 渲染虚拟DOM(元素)
语法: ReactDOM.render(virtualDOM, containerDOM)
作用: 将虚拟DOM元素渲染到页面中的真实容器DOM中显示
参数说明
参数一: 纯js或jsx创建的虚拟dom对象
参数二: 用来包含虚拟DOM元素的真实dom元素对象(一般是一个div)
1.3.4 JSX练习
需求: 动态展示如下列表
1.4 模块与组件、模块化与组件化的理解
1.4.1 模块
理解:向外提供特定功能的js程序, 一般就是一个js文件
为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂。
作用:复用js, 简化js的编写, 提高js运行效率
1.4.2 组件
理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image等等)
为什么要用组件: 一个界面的功能更复杂
作用:复用编码, 简化项目编码, 提高运行效率
1.4.3 模块化
当应用的js都以模块来编写的, 这个应用就是一个模块化的应用
1.4.4 组件化
当应用是以多组件的方式实现, 这个应用就是一个组件化的应用
第2章:React面向组件编程
2.1. 基本理解和使用
2.1.1. 使用React开发者工具调试
2.1.2. 效果
函数式组件:
类式组件:
2.1.3. 注意
组件名必须首字母大写
虚拟DOM元素只能有一个根元素
虚拟DOM元素必须有结束标签
2.1.4. 渲染类组件标签的基本流程
React内部会创建组件实例对象
调用render()得到虚拟DOM, 并解析为真实DOM
插入到指定的页面元素内部
2.2. 组件三大核心属性1: state
2.2.1. 效果
需求: 定义一个展示天气信息的组件
默认展示天气炎热 或 凉爽
点击文字切换天气
2.2.2. 理解
state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
组件被称为"状态机",通过更新组件的state来更新对应的页面显示(重新渲染组件)
2.2.3. 强烈注意
组件中render方法中的this为组件实例对象
组件自定义的方法中this为undefined,如何解决?
a. 强制绑定this: 通过函数对象的bind()
b. 箭头函数
- 状态数据,不能直接修改或更新
2.3. 组件三大核心属性2: props
2.3.1. 效果
需求: 自定义用来显示一个人员信息的组件
姓名必须指定,且为字符串类型;
性别为字符串类型,如果性别没有指定,默认为男
年龄为字符串类型,且为数字类型,默认值为18
2.3.2. 理解
每个组件对象都会有props(properties的简写)属性
组件标签的所有属性都保存在props中
2.3.3. 作用
通过标签属性从组件外向组件内传递变化的数据
注意: 组件内部不要修改props数据
2.3.4. 编码操作
- 内部读取某个属性值
- 对props中的属性值进行类型限制和必要性限制
第一种方式(React v15.5 开始已弃用):
第二种方式(新):使用prop-types库进限制(需要引入prop-types库)
- 扩展属性: 将对象的所有属性通过props传递
- 默认属性值:
5. 组件类的构造函数
2.4. 组件三大核心属性3: refs与事件处理
2.4.1. 效果
需求: 自定义组件, 功能说明如下:
1. 点击按钮, 提示第一个输入框中的值
2. 当第2个输入框失去焦点时, 提示这个输入框中的值
2.4.2. 理解
组件内的标签可以定义ref属性来标识自己
2.4.3. 编码
字符串形式的ref
回调形式的ref
createRef创建ref容器·
2.4.4. 事件处理
- 通过onXxx属性指定事件处理函数(注意大小写)
React使用的是自定义(合成)事件, 而不是使用的原生DOM事件
React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
- 通过event.target得到发生事件的DOM元素对象
2.5. 收集表单数据
2.5.1. 效果
需求: 定义一个包含表单的组件
输入用户名密码后, 点击登录提示输入信息
2.5.2. 理解
包含表单的组件分类
受控组件
非受控组件
2.6. 组件的生命周期
2.6.1. 效果
需求:定义组件实现以下功能:
1. 让指定的文本做显示 / 隐藏的渐变动画
2. 从完全可见,到彻底消失,耗时2S
3. 点击"不活了"按钮从界面中卸载组件
2.6.2. 理解
组件从创建到死亡它会经历一些特定的阶段。
React组件中包含一系列勾子函数(生命周期回调函数),会在特定的时刻调用。
我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。
2.6.3. 生命周期流程图(旧)
生命周期的三个阶段(旧)
1. 初始化阶段: 由ReactDOM.render()触发—初次渲染
constructor()
componentWillMount()
render()
componentDidMount()
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount()
2.6.4. 生命周期流程图(新)
生命周期的三个阶段(新)
1. 初始化阶段: 由ReactDOM.render()触发—初次渲染
constructor()
getDerivedStateFromProps
render()
componentDidMount()
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
getDerivedStateFromProps
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate
componentDidUpdate()
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount()
2.6.5. 重要的勾子
render:初始化渲染或更新渲染调用
componentDidMount:开启监听, 发送ajax请求
componentWillUnmount:做一些收尾工作, 如: 清理定时器
2.6.6. 即将废弃的勾子
componentWillMount
componentWillReceiveProps
componentWillUpdate
现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。
2.7. 虚拟DOM与DOM Diffing算法
2.7.1. 效果
需求:验证虚拟DOM Diffing算法的存在
2.7.2. 基本原理图
第3章:React应用(基于React脚手架)
3.1. 使用create-react-app创建react应用
3.1.1. react脚手架
- xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目
包含了所有需要的配置(语法检查、jsx编译、devServer…)
下载好了所有相关的依赖
可以直接运行一个简单效果
react提供了一个用于创建react项目的脚手架库: create-react-app
项目的整体技术架构为: react + webpack + es6 + eslint
使用脚手架开发的项目的特点: 模块化, 组件化, 工程化
3.1.2. 创建项目并启动
第一步,全局安装:npm i -g create-react-app
第二步,切换到想创项目的目录,使用命令:create-react-apphello-react
第三步,进入项目文件夹:cd hello-react
第四步,启动项目:npm start
3.1.3. react脚手架项目结构
public ---- 静态资源文件夹
favicon.icon ------ 网站页签图标
index.html -------- 主页面
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件
robots.txt -------- 爬虫协议文件
src ---- 源码文件夹
App.css -------- App组件的样式
App.js --------- App组件
App.test.js ---- 用于给App做测试
index.css ------ 样式
index.js ------- 入口文件
logo.svg ------- logo图
reportWebVitals.js — 页面性能分析文件(需要web-vitals库的支持)
setupTests.js ---- 组件单元测试的文件(需要jest-dom库的支持)
3.1.4. 功能界面的组件化编码流程(通用)
1. 拆分组件: 拆分界面,抽取组件
2. 实现静态组件: 使用组件实现静态页面效果
3. 实现动态组件
3.1 动态显示初始化数据
3.1.1 数据类型
3.1.2 数据名称
3.1.2 保存在哪个组件?
3.2 交互(从绑定事件监听开始)
3.2. 组件的组合使用-TodoList
功能: 组件化实现此功能
1. 显示所有todo列表
2. 输入文本, 点击按钮显示到列表的首位, 并清除输入的文本
第4章:React ajax
4.1. 理解
4.1.1. 前置说明
React本身只关注于界面, 并不包含发送ajax请求的代码
前端应用需要通过ajax请求与后台进行交互(json数据)
react应用中需要集成第三方ajax库(或自己封装)
4.1.2. 常用的ajax请求库
jQuery: 比较重, 如果需要另外引入不建议使用
axios: 轻量级, 建议使用
封装XmlHttpRequest对象的ajax
promise风格
可以用在浏览器端和node服务器端
4.2. axios
4.2.1. 文档
https://github.com/axios/axios
4.2.2. 相关API
- GET请求
axios.get('/user?ID=12345').then(function (response) {console.log(response.data);}).catch(function (error) {console.log(error);});axios.get('/user', {params: {ID: 12345}}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);});
- POST请求
axios.post('/user', {firstName: 'Fred',lastName: 'Flintstone'
})
.then(function (response) {console.log(response);
})
.catch(function (error) {console.log(error);
});
4.3. 案例—github用户搜索
4.3.1. 效果
请求地址: https://api.github.com/search/users?q=xxxxxx
4.4. 消息订阅-发布机制
工具库: PubSubJS
下载: npm install pubsub-js --save
使用:
import PubSub from ‘pubsub-js’ //引入
PubSub.subscribe(‘delete’, function(data){ }); //订阅
PubSub.publish(‘delete’, data) //发布消息
4.5. 扩展:Fetch
4.5.1. 文档
[https://github.github.io/fetch/]{.ul}
[https://segmentfault.com/a/1190000003810652]{.ul}
4.5.2. 特点
fetch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求
老版本浏览器可能不支持
4.5.3. 相关API
- GET请求
fetch(url).then(function(response) {return response.json()}).then(function(data) {console.log(data)}).catch(function(e) {console.log(e)});
- POST请求
fetch(url, {method: "POST",body: JSON.stringify(data),}).then(function(data) {console.log(data)}).catch(function(e) {console.log(e)})
第5章:React路由
5.1. 相关理解
5.1.1. SPA的理解
单页Web应用(single page web application,SPA)。
整个应用只有一个完整的页面。
点击页面中的链接不会刷新页面,只会做页面的局部更新。
数据都需要通过ajax请求获取, 并在前端异步展现。
5.1.2. 路由的理解
- 什么是路由?
一个路由就是一个映射关系(key:value)
key为路径, value可能是function或component
- 路由分类
(1)后端路由:
1. 理解: value是function, 用来处理客户端提交的请求。2. 注册路由: router.get(path, function(req, res))3. 工作过程:当node接收到一个请求时,根据请求路径找到匹配的路由, 调用路由中的函数来处理请求,返回响应数据
(2) 前端路由:
1. 浏览器端路由,value是component,用于展示页面内容。2. 注册路由: \<Route path=\"/test\" component={Test}>3. 工作过程:当浏览器的path变为/test时,当前路由组件就会变为Test组件
5.1.3. react-router-dom的理解
react的一个插件库。
专门用来实现一个SPA应用。
基于react的项目基本都会用到此库。
5.2. react-router-dom相关API
5.2.1. 内置组件
<BrowserRouter>
<HashRouter>
<Route>
<Redirect>
<Link>
<NavLink>
<Switch>
5.2.2. 其它
history对象
match对象
withRouter函数
5.3. 基本路由使用
5.3.1. 效果
5.3.2. 准备
下载react-router-dom: npm install --save react-router-dom
引入bootstrap.css: <link rel=“stylesheet"href=”/css/bootstrap.css">
5.4. 嵌套路由使用
效果
5.5. 向路由组件传递参数数据
效果
5.6. 多种路由跳转方式
效果
第6章:React UI组件库
6.1.流行的开源React UI组件库
6.1.1. material-ui(国外)
官网: http://www.material-ui.com/#/
github: https://github.com/callemall/material-ui
6.1.2. ant-design(国内蚂蚁金服)
官网: https://ant.design/index-cn
Github: https://github.com/ant-design/ant-design/
第7章:redux
7.1. redux理解
7.1.1. 学习文档
英文文档: https://redux.js.org/
中文文档: http://www.redux.org.cn/
Github: https://github.com/reactjs/redux
7.1.2. redux是什么
redux是一个专门用于做状态管理的JS库(不是react插件库)。
它可以用在react, angular, vue等项目中, 但基本与react配合使用。
作用: 集中式管理react应用中多个组件共享的状态。
7.1.3. 什么情况下需要使用redux
某个组件的状态,需要让其他组件可以随时拿到(共享)。
一个组件需要改变另一个组件的状态(通信)。
总体原则:能不用就不用, 如果不用比较吃力才考虑使用。
7.1.4. redux工作流程
7.2. redux的三个核心概念
7.2.1. action
动作的对象
包含2个属性
type:标识属性, 值为字符串, 唯一, 必要属性
data:数据属性, 值类型任意, 可选属性
- 例子:{ type: ‘ADD_STUDENT’,data:{name: ‘tom’,age:18} }
7.2.2. reducer
用于初始化状态、加工状态。
加工时,根据旧的state和action, 产生新的state的纯函数。
7.2.3. store
将state、action、reducer联系在一起的对象
如何得到此对象?
import {createStore} from ‘redux’
import reducer from ‘./reducers’
const store = createStore(reducer)
- 此对象的功能?
getState(): 得到state
dispatch(action): 分发action, 触发reducer调用, 产生新的state
subscribe(listener): 注册监听, 当产生了新的state时, 自动调用
7.3. redux的核心API
7.3.1. createstore()
作用:创建包含指定reducer的store对象
7.3.2. store对象
作用: redux库最核心的管理对象
它内部维护着:
state
reducer
- 核心方法:
getState()
dispatch(action)
subscribe(listener)
- 具体编码:
store.getState()
store.dispatch({type:‘INCREMENT’, number})
store.subscribe(render)
7.3.3. applyMiddleware()
作用:应用上基于redux的中间件(插件库)
7.3.4. combineReducers()
作用:合并多个reducer函数
7.4. 使用redux编写应用
效果
7.5. redux异步编程
7.5.1理解:
redux默认是不能进行异步处理的,
某些时候应用中需要在redux中执行异步任务(ajax, 定时器)
7.5.2. 使用异步中间件
npm install --save redux-thunk
7.6. react-redux
7.6.1. 理解
一个react插件库
专门用来简化react应用中使用redux
7.6.2. react-Redux将所有组件分成两大类
- UI组件
只负责 UI 的呈现,不带有任何业务逻辑
通过props接收数据(一般数据和函数)
不使用任何 Redux 的 API
一般保存在components文件夹下
- 容器组件
负责管理数据和业务逻辑,不负责UI的呈现
使用 Redux 的 API
一般保存在containers文件夹下
7.6.3. 相关API
Provider:让所有组件都可以得到state数据
connect:用于包装 UI 组件生成容器组件
mapStateToprops:将外部的数据(即state对象)转换为UI组件的标签属性
mapDispatchToProps:将分发action的函数转换为UI组件的标签属性
7.7. 使用上redux调试工具
7.7.1. 安装chrome浏览器插件
7.7.2. 下载工具依赖包
npm install --save-dev redux-devtools-extension
7.8. 纯函数和高阶函数
7.8.1. 纯函数
一类特别的函数: 只要是同样的输入(实参),必定得到同样的输出(返回)
必须遵守以下一些约束
不得改写参数数据
不会产生任何副作用,例如网络请求,输入和输出设备
不能调用Date.now()或者Math.random()等不纯的方法
- redux的reducer函数必须是一个纯函数
7.8.2. 高阶函数
- 理解: 一类特别的函数
情况1: 参数是函数
情况2: 返回是函数
- 常见的高阶函数:
定时器设置函数
数组的forEach()/map()/filter()/reduce()/find()/bind()
promise
react-redux中的connect函数
- 作用: 能实现更加动态, 更加可扩展的功能
第8章 react 扩展
1. setState
setState更新状态的2种写法
(1). setState(stateChange, [callback])------对象式的setState1.stateChange为状态改变对象(该对象可以体现出状态的更改)2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用(2). setState(updater, [callback])------函数式的setState1.updater为返回stateChange对象的函数。2.updater可以接收到state和props。4.callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
总结:1.对象式的setState是函数式的setState的简写方式(语法糖)2.使用原则:(1).如果新状态不依赖于原状态 ===> 使用对象方式(推荐)(2).如果新状态依赖于原状态 ===> 使用函数方式(推荐)(3).如果需要在setState()执行后获取最新的状态数据, 要在第二个callback函数中读取
App.js:
Demo组件:
2. lazyLoad
路由组件的lazyLoad
//1.通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包const Login = lazy(()=>import('@/pages/Login'))//2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面<Suspense fallback={<h1>loading.....</h1>}><Switch><Route path="/xxx" component={Xxxx}/><Redirect to="/login"/></Switch></Suspense>
3. Hooks
1. React Hook/Hooks是什么?
(1). Hook是React 16.8.0版本增加的新特性/新语法
(2). 可以让你在函数组件中使用 state 以及其他的 React 特性
2. 三个常用的Hook
(1). State Hook: React.useState()
(2). Effect Hook: React.useEffect()
(3). Ref Hook: React.useRef()
3. State Hook
(1). State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作
(2). 语法: const [xxx, setXxx] = React.useState(initValue)
(3). useState()说明:参数: 第一次初始化指定的值在内部作缓存返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数
(4). setXxx()2种写法:setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
4. Effect Hook
(1). Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
(2). React中的副作用操作:发ajax请求数据获取设置订阅 / 启动定时器手动更改真实DOM
(3). 语法和说明: useEffect(() => { // 在此可以执行任何带副作用操作return () => { // 在组件卸载前执行// 在此做一些收尾工作, 比如清除定时器/取消订阅等}}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行(4). 可以把 useEffect Hook 看做如下三个函数的组合componentDidMount()componentDidUpdate()componentWillUnmount()
5. Ref Hook
(1). Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据
(2). 语法: const refContainer = useRef()
(3). 作用:保存标签对象,功能与React.createRef()一样
代码演示:
import React from 'react'
import ReactDOM from 'react-dom'// 类式组件
/*
class Demo extends React.Component {state = {count:0}myRef = React.createRef()add = ()=>{this.setState(state=>({count:state.count+1}))}unmount = ()=>{ReactDOM.unmountComponentAtNode(document.getElementById('root'))}show = ()=>{alert(this.myRef.current.value)}componentDidMount(){this.timer = setInterval(()=>{this.setState(state=>({count:state.count+1}))},1000)}componentWillUnmount(){clearInterval(this.timer);}render() {return (<div><input type="text" ref={this.myRef}/><h1>当前求和为:{this.state.count}</h1><button onClick={this.add}>点我+1</button><button onClick={this.unmount}>点我卸载组件</button><button onClick={this.show}>点我弹框</button></div>)}
}
*/// 函数式组件
function Demo(){const [count,setCount] = React.useState(0)const myRef = React.useRef()// useEffect函数相当于componentDidMount + componentDidUpdate + componentWillUnmount (componentWillUnmount相当于useEffect返回的函数)React.useEffect(()=>{let timer = setInterval(()=>{setCount(count => count+1)},1000)return ()=>{clearInterval(timer)}},[]) // 如果指定的是[], 回调函数只会在第一次render()后执行function add(){// 第一种写法// setCount(count+1)// 第二种写法setCount(count => count+1)}function unmount(){ReactDOM.unmountComponentAtNode(document.getElementById('root'))}function show(){alert(myRef.current.value)}return (<div><input type="text" ref={myRef}/><h1>当前求和为:{count}</h1><button onClick={add}>点我+1</button><button onClick={unmount}>点我卸载组件</button><button onClick={show}>点我弹框</button></div>)
}export default Demo
4. Fragment
使用
<Fragment><Fragment>
<></>
作用
可以不用必须有一个真实的DOM根标签了
代码演示:
import React, { Component,Fragment } from 'react'export default class Demo extends Component {render() {return (// 如果是空标签,不允许写任何属性// Fragment只能拥有一个key属性<Fragment key={1}><h1>你好,react!</h1><h2>你好,react!</h2></Fragment>)}
}
5. Context
理解
一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信
使用
1) 创建Context容器对象:const XxxContext = React.createContext() 2) 渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:<xxxContext.Provider value={数据}>子组件</xxxContext.Provider>3) 后代组件读取数据://第一种方式:仅适用于类组件 static contextType = xxxContext // 声明接收contextthis.context // 读取context中的value数据//第二种方式: 函数组件与类组件都可以<xxxContext.Consumer>{value => ( // value就是context中的value数据要显示的内容)}</xxxContext.Consumer>
注意
在应用开发中一般不用context, 一般都用它的封装react插件
import React, { Component } from 'react'
import './index.css'// 创建Context对象
const MyContext = React.createContext()
export default class A extends Component {state = {username:'tom',age:22}render() {const {username,age} = this.statereturn (<div className="parent"><h1>我是A组件</h1><h2>我的用户名是:{username}</h2><MyContext.Provider value={{username,age}}><B/> </MyContext.Provider></div>)}
}
class B extends Component {render() {return (<div className="child"><h1>我是B组件</h1><C/></div>)}
}// class C extends Component {
// // 声明接收context
// static contextType = MyContext
// render() {// const {username,age} = this.context
// return (
// <div className="grand">
// <h1>我是C组件</h1>
// <h2>我的用户名是:{username},年龄是:{age}</h2>
// </div>
// )
// }
// }function C(){return(<div className="grand"><h1>我是C组件</h1><h2>我的用户名是:<MyContext.Consumer>{value =>{return `${value.username},年龄是:${value.age}`}}</MyContext.Consumer></h2></div>)
}
6. 组件优化
Component的2个问题
只要执行setState(),即使不改变状态数据, 组件也会重新render() ==> 效率低
只当前组件重新render(), 就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==> 效率低
效率高的做法
只有当组件的state或props数据发生改变时才重新render()
原因
Component中的shouldComponentUpdate()总是返回true
解决
办法1: 重写shouldComponentUpdate()方法比较新旧state或props数据, 如果有变化才返回true, 如果没有返回false
办法2: 使用PureComponentPureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true注意: 只是进行state和props数据的浅比较, 如果只是数据对象内部数据变了, 返回false 不要直接修改state数据, 而是要产生新数据
项目中一般使用PureComponent来优化
代码演示:
import React, { PureComponent } from 'react'
import './index.css'export default class Parent extends PureComponent {state = {carName:"奔驰c63"}changeCar = ()=>{this.setState({carName:"迈巴赫"})}// shouldComponentUpdate(nextProps,nextState){ // return !this.state.carName===nextState.carName// }render() {console.log('Parent---render');const {carName} = this.statereturn (<div className="parent"><h1>我是Parenet组件</h1><span>我开的车是: {carName}</span><br/><button onClick={this.changeCar}>点我换车</button><Child carName="宝马"/></div>)}
}class Child extends PureComponent {// shouldComponentUpdate(nextProps,nextState){// console.log(this.props,this.state);// console.log(nextProps,nextState);// return !this.props.carName===nextProps.carName// }render() {console.log('Child---render');return (<div className="child"><h1>我是Child组件</h1><span>我接到的车是:{this.props.carName}</span></div>)}
}
7. render props
如何向组件内部动态传入带内容的结构(标签)?
Vue中: 使用slot技术, 也就是通过组件标签体传入结构 <A><B/></A>
React中:使用children props: 通过组件标签体传入结构使用render props: 通过组件标签属性传入结构,而且可以携带数据,一般用render函数属性
children props
<A><B>xxxx</B>
</A>
{this.props.children}
问题: 如果B组件需要A组件内的数据, ==> 做不到
render props
<A render={(data) => <C data={data}></C>}></A>
A组件: {this.props.render(内部state数据)}
C组件: 读取A组件传入的数据显示 {this.props.data}
代码演示:
import React, { Component } from 'react'
import './index.css'
export default class Parent extends Component {render() {return (<div className="parent"><h1>我是Parent组件</h1><A render={(name)=><B name={name}/>}/></div>)}
}
class A extends Component {state = {name:'tom'} render() {const {name} = this.statereturn (<div className="a"><h1>我是A组件</h1>{this.props.render(name)}</div>)}
}
class B extends Component {render() {return (<div className="b"><h1>我是B组件</h1>{this.props.name}</div>)}
}
8. 错误边界
理解:
错误边界(Error boundary):用来捕获后代组件错误,渲染出备用页面
特点:
只能捕获后代组件生命周期产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件、定时器中产生的错误
使用方式:
getDerivedStateFromError配合componentDidCatch
// 生命周期函数,一旦后台组件报错,就会触发
static getDerivedStateFromError(error) {console.log(error);// 在render之前触发// 返回新的statereturn {hasError: true,};
}componentDidCatch(error, info) {// 统计页面的错误。发送请求发送到后台去console.log(error, info);
}
代码演示:
Parent.jsx:
import React, { Component } from 'react'
import Child from './Child'export default class Parent extends Component {state = {hasError:'' //用于标识子组件是否产生错误}//当Parent的子组件出现报错时候,会触发getDerivedStateFromError调用,并携带错误信息static getDerivedStateFromError(error){console.log('@@@',error);return {hasError:error}}componentDidCatch(){console.log('此处统计错误,反馈给服务器,用于通知编码人员进行bug的解决');}render() {return (<div><h2>我是Parent组件</h2>{this.state.hasError ? <h2>当前网络不稳定,稍后再试</h2> : <Child/>}</div>)}
}
Child.jsx:
import React, { Component } from 'react'export default class Child extends Component {state = {// users:[// {id:'001',name:'tom',age:18},// {id:'002',name:'jack',age:19},// {id:'003',name:'peiqi',age:20},// ]users:'abc'}render() {return (<div><h2>我是Child组件</h2>{this.state.users.map((userObj)=>{return <h4 key={userObj.id}>{userObj.name}----{userObj.age}</h4>})}</div>)}
}
9. 组件通信方式总结
组件间的关系:
- 父子组件
- 兄弟组件(非嵌套组件)
- 祖孙组件(跨级组件)
几种通信方式:
1.props:(1).children props(2).render props2.消息订阅-发布:pubs-sub、event等等3.集中式管理:redux、dva等等4.conText:生产者-消费者模式
比较好的搭配方式:
父子组件:props兄弟组件:消息订阅-发布、集中式管理祖孙组件(跨级组件):消息订阅-发布、集中式管理、conText(开发用的少,封装插件用的多)
B站尚硅谷React入门教程相关推荐
- 【YY笔记】React.入门(尚硅谷React教程笔记)
前言 教程链接:尚硅谷React技术全家桶全套完整版:天禹老师讲得挺好,感谢免费分享教程 笔记用OneNote记的,不想重写了,但是想保留格式就只能用图片传上来--很烦 可能会有一些疏漏和小白的地方, ...
- JavaScript(基础、高级)笔记汇总表【尚硅谷JavaScript全套教程完整版】
目 录 前言 JavaScript(基础+高级)配套资料下载 JavaScript 基础 学习地址 学习笔记 day 05(P001-P006)[2016.11.22] day 06(P007-P ...
- JavaWeb学习笔记(5)-B站尚硅谷
文章目录 十四.书城项目第三阶段--优化 (1)页面jsp动态化 (2)抽取页面中相同的内容 A.登录成功的菜单 B.base.css.jQuery标签 C.每个页面的页脚 D.manager模块的菜 ...
- 尚硅谷JavaScript高级教程(javascript实战进阶)学习笔记
前言 这个是我学习过程中的笔记,分享给大家,希望对大家有用. 学习内容是尚硅谷JavaScript高级教程(javascript实战进阶),这里是视频链接. 我在前面有两篇对于web前端HTML和CS ...
- 尚硅谷Docker实战教程-笔记02【安装docker、镜像加速器配置】
尚硅谷大数据技术-教程-学习路线-笔记汇总表[课程资料下载] 视频地址:尚硅谷Docker实战教程(docker教程天花板)_哔哩哔哩_bilibili 尚硅谷Docker实战教程-笔记01[理念简介 ...
- Vue数据代理+事件处理+事件修饰符的作用+计算属性的使用,尚硅谷Vue系列教程学习笔记(2)
尚硅谷Vue系列教程学习笔记(2) 参考课程:<尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通> 参考链接:https://www.bilibili.com/video/ ...
- b站尚硅谷springmvc学习视频:springmvc文档
文章目录 一.SpringMVC简介 (b站尚硅谷springmvc学习视频:springmvc文档) 1.什么是MVC 2.什么是SpringMVC 3.SpringMVC的特点 二.HelloWo ...
- JDBC学习笔记(1)---B站尚硅谷宋红康
JDBC学习笔记(1)-B站尚硅谷宋红康 JDBC学习笔记(2)-B站尚硅谷宋红康 文章目录 软件架构方式介绍 JavaWeb技术概览 第1章:JDBC概述 1.1 数据的持久化 1.2 Java中的 ...
- 尚硅谷Java入门视频教程导读及第一章
尚硅谷Java入门视频教程导读及第一章 JAVA基础学习导读-编程入门 0.1概述 0.2 计算机硬件介绍 中央处理器(CPU) 存储设备 内存 比特(bit)和字节(byte) 内存 输入和输出设备 ...
最新文章
- LeetCode Decode Ways
- c# string总结
- Lucene学习总结之七:Lucene搜索过程解析
- 反向图——dj算法(判断从起点 开始有没有第二条路径能到达)Gym 102501K
- 各种说明方法的答题格式_语文万能答题公式,给孩子收藏吧!
- Android通知点击事件传递参数
- 在大公司天天调参数,感觉快废了~
- form.html,HTML表单form
- Angularjs编写KindEditor,UEidtor指令
- 游戏用户被锁定后出现的错误提示
- 【QQ机器人】来认领一只派蒙Bot吧:QQ娱乐机器人,免费开源、易搭建、20余种功能集成、可扩展
- 微分销机制设计_免费快速搭建微信分销商城_OctShop源码
- React纯前端生成word文档(支持多图片导出)
- Day06(上)C++继承和派生
- c语言怎样自动对齐,c语言自动对齐原则
- 机器学习OneR算法
- 磊科nw362 linux驱动下载,磊科nw362无线网卡驱动
- #torch.bmm()函数解读
- c语言怎么写tg的反函数,关于y=x对称的两个函数表达式有什么特点 改怎么写 比如对数函数...
- RuoYi框架放行vue和某些公开接口
热门文章
- 【Java】Java安装与配置指南
- Java基础语法-环境搭建及入门
- 基于人脸识别的考勤系统:Python3 + Qt5 + OpenCV3 + FaceNet + MySQL
- 推荐--jQuery使用手册 1
- Precision,Recall,F1score,Accuracy的理解
- vmware安装linux虚拟机
- java 转成数字,java汉字转成数字
- 删除vSphere中DataStore(inactive)非活动存储
- LightWave 3D 2019 for Mac(三维动画制作软件)
- java反射的作用于原理、初学者