安装
懂王的React说明文档
环境安装
npm config set registry https://registry.npmmirror.com
环境查看
npm config get registry
安装React运行环境
npx create-react-app my-app
cd my-app
npm start
入口文件
.
严格模式的作用
不安全的生命周期方法:某些生命周期方法在未来的React版本中将被弃用。严格模式会警告这些不安全的方法的使用。
使用过时或遗留的API:严格模式会警告使用过时或遗留的API。
意外的副作用:严格模式可以帮助你发现组件中可能的意外副作用。
与旧版本React不兼容的代码:严格模式会警告你的代码中可能与未来版本的React不兼容的部分
React和ReactDom两个包分别有什么作用?
react
:这是React库的核心。它定义了React组件的创建和生命周期方法,以及React元素的概念。你可以将其视为React的"引擎"。
react-dom
:这个库提供了在浏览器环境中使用React的方法,例如将React组件渲染到DOM中,或者在DOM中触发React组件的更新。你可以将其视为React的"驱动程序"。
创建第一个React组件
JSX语法,需要经过编译,babel

React创建组件有两种方式
-
Class (已被官方推荐废弃,但是需要了解学习,为函数式组件做铺垫)
-
Fuction纯函数 (后续都会用这种方式 hooks)
生命周期

componentDidMount
组件挂载时执行
static getDerivedStateFromProps(props, state)
如果你定义了 static getDerivedStateFromProps
,React 会在初始挂载和后续更新时调用 render 之前调用它。它应该返回一个对象来更新 state,或者返回 null
就不更新任何内容。
-
props
:组件即将用来渲染的下一个 props。 -
state
:组件即将渲染的下一个 state。
getSnapshotBeforeUpdate(prevProps, prevState)
如果你实现了 getSnapshotBeforeUpdate
,React 会在 React 更新 DOM 之前时直接调用它。它使你的组件能够在 DOM 发生更改之前捕获一些信息(例如滚动的位置)。此生命周期方法返回的任何值都将作为参数传递给 componentDidUpdate。
React官网
进入Hooks
-
hooks真正的把react思想运用的淋漓尽致,彻底让你感觉写React=写JS
-
hooks非常的神奇,一个钩子可以几乎实现Class类组件中的所有生命周期。
-
hooks非常的奇葩,一个钩子居然可以实现Class类组件中的所有生命周期。
-
hooks的学习难度指数级上升,因为它太灵活了!
-
Vue居然不顾一切的要抄袭hooks???形似神不似,React才是祖师爷
useEffect
参数:
-
更新的回调函数
-
依赖项?
a.[]
import { useEffect } from 'react';
function App() {
useEffect(() => {
console.log('useEffect执行')
})return (
hello hooks
)
}
执行时机:
-
组件初始化
-
组件更新之后执行(浏览器渲染更新完成之后)
当我传入依赖项 []
useEffect(() => {
console.log('useEffect执行')
},[])
执行时机:
- 组件初始化、挂载
当我们传入依赖项[a], 当传入多个依赖项的时候[a,b], a或者b发生变化都执行
-
初始化执行
-
依赖的状态发生变化会执行
当第二个依赖项不传的时候
-
初始化
-
组件内定义的state都是依赖项,发生变化就执行
useEffect返回的函数执行时机
-
组件卸载的时候
-
状态发生变化的时候执行
应用场景是什么?
useState
一个小案例
import { useEffect, useState } from 'react';
import './App.css';
function App() {
const [count, setCount] = useState(0) // [0, function(){}
const [name, setName] = useState(() => {
return '张三'
}) // ['张三', function(){}
// 第一个参数回调函数:组件初始化执行,组件更新之后会执行(dom更新完成)
useEffect(() => {
console.log('useEffect执行')
return () => {
console.log('组件卸载')
}
},[])
function btn_click() {
setCount((count) => {
return count + 1
})
// count是几? 实际执行的结果是0。
// react的组件状态更新是异步队列的,为了性能。
console.log(count)
}
function btn_click2() {
setName('李四')
}
return (
<div>
<h1>{count}</h1>
<h1>{name}</h1>
<button onClick={btn_click}>点我+1</button>
<button onClick={btn_click2}>点我修改名字</button>
</div>
)
}
export default App;
useLayoutEffect
应用场景: 见第十一课demo
useMemo
它是用于react渲染过程 中的性能优化。
适用于: 父组件要进行更新,子组件的重新render计算量比较大,而且结果可以复用。就可以使用useMemo来提升父组件引起子组件不必要渲染的性能优化。
useCallback
对函数引用的缓存
React.memo
可以阻止父组件渲染引起的子组件(组件本身)更新。
name
age
old
useRef
可以获取组件中的dom实例
import React, { useRef, useEffect } from 'react';
function Example() {
const inputRef = useRef(null);
console.log('inputRef', inputRef)
useEffect(() => {
console.log('inputRef useEffect中执行的', inputRef)
inputRef.current.focus();
// console.log('input', input)
}, []);
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={() => inputRef.current.focus()}>Focus Input</button>
</div>
);
}
export default Example
useContext
跨组件传值
useTransition
演示React真正意义上比Vue厉害的地方。
用于性能,用于用户体验。
特性: 并发更新(fiber架构),16.8版本之后
并发更新
fiber架构
分片更新
异步更新
见面试题部分
useDefferedValue
use
canary特性,金丝雀特性
useDebugValue
这个调试工具需要在严格模式之下开启

useId
在React组件渲染过程中生成一个ID
这个ID是根据react组件树的位置相关,不是随机的。每次生成都一样
为什么不能用随机数?
因为有一种场景,Nodejs端去做React的服务端渲染(SSR 20K以上工程师要会的技术)。
需要确保Node端生成Id和前端(浏览器)一致。
useImperativeHandle
自定义ref, 通过forwardRefs转发出去
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focusInput: () => {
inputRef.current.focus();
},
getValue: () => {
return inputRef.current.value;
}
}));
return (
<div>
<input ref={inputRef} type="text" />
</div>
);
});
export default function App() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focusInput();
};
const getValue = () => {
const value = inputRef.current.getValue();
console.log(value);
};
return (
<div>
<CustomInput ref={inputRef} />
<button onClick={focusInput}>Focus Custom Input</button>
<button onClick={getValue}>Get Value</button>
</div>
);
}
useInsertionEffect
useInsertionEffect
是为 CSS-in-JS 库的作者特意打造的。
如果你需要使用js插入style标签,请使用useInsertionEffect。
不要用其他,否则可能发生错误。
useSyncExternalStore
也是库的作者去使用的。
解决tearing,状态撕裂问题(react并发更新带来的问题)。
后续要学的:
路由 router
状态管理 redux
面试题
React和React-Dom的区别?为什么有两个库?
1.react
:这是React库的核心。它定义了React组件的创建和生命周期方法,以及React元素的概念。你可以将其视为React的"引擎"。
2.react-dom
:这个库提供了在浏览器环境中使用React的方法,例如将React组件渲染到DOM中,或者在DOM中触发React组件的更新。你可以将其视为React的"驱动程序"。补充:
react-dom/client是浏览器渲染用的库,同理node端也有对应的库。
为什么有多个包,为了功能解耦,渲染有渲染专用的包,引擎就只负责引擎。
React是框架吗?
react的核心,其实是一个渲染的库。
React严格模式的作用?
1. 不安全的生命周期方法:某些生命周期方法在未来的React版本中将被弃用。严格模式会警告这些不安全的方法的使用。
2. 使用过时或遗留的API:严格模式会警告使用过时或遗留的API。
3. 意外的副作用:严格模式可以帮助你发现组件中可能的意外副作用。 防止你写一些有问题的代码
4. 与旧版本React不兼容的代码:严格模式会警告你的代码中可能与未来版本的React不兼容的部分。
Jsx的作用?
可以在js中返回dom,经过babel编译成JS认识的代码。
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
-
第一个参数: 标签名
-
第二个参数:
-
子元素
-
标签中的一些属性
-
getDerivedStateFromProps的作用是什么?
它的返回值,会对state进行相同属性覆盖,如果没有和state一样的属性就什么都不做。
执行时机: 挂载和更新都执行,在render之前。
什么场景下可以用这个方法?
- 人民币转换大小写
getSnapshotBeforeUpdate的特点
执行时机:只会更新的时候执行,在render之后,浏览器页面更新之前
作用:返回值可以传递给componentDidUpdtate
场景:
长列表,需要不断的往里面塞入内容。
更新之前,记住滚轮的位置,传递给componentDidUpdtate,保持滚轮的位置。
getSnapshotBeforeUpdate更新之前记录滚轮的原始位置,传递给componentDidUpdtate。
componentDidUpdtate就使用原始的位置更新dom,保证滚轮的正确性。
React的更新是同步还是异步?为什么?
更新是异步的。
因为React的更新底层的异步(微任务)队列,会将短时间的JS对组件的修改进行合并,1次渲染完成。
useEffect的执行时机?
看课件
useEffect的返回函数执行时机?
-
卸载
-
依赖项更新
更新的执行,实际上也是用于卸载操作。
应用场景:
组件: 扣扣 聊天工具
作用: 用于卸载。
跟A聊天,跟A建立连接。
useEffect(() => {
// A
// 伪代码
connect(user)
return () => {
console.log('effect返回的函数执行', count)
}
},[user]) // A
离开A的页面,跟B建立连接
useEffect(() => {
// B
// 伪代码
connect(user)
return () => {
// A
console.log('effect返回的函数执行', count)
disConnect(user)
}
},[user]) // A => B
Hooks的钩子为什么要写在顶层作用域?

因为组件的hooks是用链表这种数据结构来进行连接的,通过next属性保持执行顺序。
如果中间的断开,会导致后面的钩子找不到。
useEffect和useLayoutEffect的区别?

useEffect(异步)是在commit的第一个阶段,js操作dom之前调用,但是在浏览器渲染完成之后调用。
useLayoutEffect(同步),JS操作完dom之后调用,在浏览器渲染之前。
useLayoutEffect的应用场景?
见第十一课的demo
useMemo的应用场景?
它是用于react渲染过程 中的性能优化。
适用于: 父组件要进行更新,子组件的重新render计算量比较大,而且结果可以复用。就可以使用useMemo来提升父组件引起子组件不必要渲染的性能优化。
我该在哪些地方使用useMemo?
useMemo在项目中一定是不得已用才使用(已经出现了明显的问题)。
-
useMemo本身有性能消耗,缓存消耗内存,useMemo自身状态的维护也是有性能开销的
-
useMemo会增加开发成本,代码变的很复杂不好维护
-
react官方在未来会取消useMemo这个钩子
react的渲染规律?
只要父组件进行的setState,父组件本身会重新render,所有子组件也会重新render
useMemo和useCallback的区别?
实际上没有本质区别,只是一个用于缓存函数,一个用于缓存数据。
纯粹为了代码的可维护性。
forwardRef的作用?
实际上函数式组件是没有ref的。
那我们想拿到函数组件内部某个dom实例,就可以通过forwardRef转发出去。
useContext的作用?
主要用于跨组件传值。
核心是父组件使用Provider包裹,给所有子组件注入上下文(值)。
子孙组件就可以通过useContext拿到顶层组件注入的值。
一般修改状态,可以把状态和修改函数一并注入。
React并发更新的作用?
-
基于Fiber数据结构,进行细粒度的任务拆分
-
在浏览器空闲时间执行,requestIdleCallback 的思想
因为requestIdleCallback这个东西兼容性不好,React目前是使用PostMessage去模拟实现的,它是宏任务的异步。

useTransition和useDeferredValue的区别?
解决的问题是一样的。
只是应用场景有点细微的区别。
一般useDeferredValue比较适合用于组件接受的Props参数导致渲染缓慢的优化。
useTransition比较适合在自己组件内部本身来进行优化。
场景:
写了两个组件:
TabContainer也是一个组件,假设是我自己开发的,我提供给别人使用。但是我希望这个组件,别人拿来用的时候已经是性能不错的,就可以使用useTransition。
SlowList是一个组件,假设是别的团队开发的,我是组件使用者。使用者想优化这个组件的渲染,把它变成低优先级就可以使用useDeferredValue。
react的hook一定要写在顶层作用域吗?
不是的,比如说use这个hook就不用,这是一个特殊的存在。
useDebugValue的作用?
可以利用调试工具,做组件级别的debug。全部用console堆在一起,不方便。
记得开启严格模式!!!
useId的应用场景?
场景:多个密码确定框。
为什么不能用随机数?
因为有一种场景,Nodejs端去做React的服务端渲染(SSR 20K以上工程师要会的技术)。
需要确保Node端生成Id和前端(浏览器)一致。
useImperativeHandle的应用场景?
作用: 自定义转发出去的ref
应用场景: 我不希望开发者直接操作dom,你用我给你定义的方法就好。
useInsertionEffect
useInsertionEffect
是为 CSS-in-JS 库的作者特意打造的。
如果你需要使用js插入style标签,请使用useInsertionEffect。
不要用其他,否则可能发生错误。
useSyncExternalStore的作用?
解决状态撕裂问题。
详情见课件
