三十四、redux开发者工具
7.求和案例_redux开发者工具的使用
(1). yarn add redux-devtools-extension
(2). store中进行配置
jsx
import { composeWithDevTools } from 'redux-devtools-extension'
const store = createStore(allReducer, composeWithDevTools(applyMiddleware(thunk)))
三十五、setState讲解

React setState 核心知识点
一、setState 的两种用法
1. 对象式 setState
-
语法 :
setState(stateChangeObj, [callback]) -
说明:
stateChangeObj:直接传入一个对象,描述要修改的状态。callback(可选):状态更新完成、render()执行后才会调用的回调函数,可在其中获取最新状态。
2. 函数式 setState
-
语法 :
setState(updaterFunc, [callback]) -
说明:
updaterFunc:一个函数,接收上一次的state和props作为参数,返回一个状态更新对象。callback(可选):和对象式用法中的回调作用一致。
二、两种写法的关系
对象式 setState 是函数式 setState 的语法糖,本质上 React 内部最终都会将对象式写法转换为函数式写法执行。
三、使用原则(核心考点)
- 新状态不依赖原状态 :优先使用对象式
setState,写法更简洁。 - 新状态依赖原状态 :必须使用函数式
setState,避免因setState异步合并导致的状态更新错误。 - 获取最新状态 :如果需要在
setState执行后立刻拿到更新后的状态值,只能在第二个参数callback回调函数中读取,不能直接在setState之后同步读取this.state。
三十六、React 路由懒加载(lazyLoad)知识点
一、核心概念
路由懒加载,就是只有当用户访问到对应路由时,才加载该路由组件的代码,而不是在应用启动时一次性加载所有组件。
- 作用:减少首屏加载时间,优化应用性能,避免打包后的主文件过大。
- 核心 API:
React.lazy()+import()+<Suspense>
二、实现步骤
1. 使用 React.lazy() 动态导入路由组件
通过 lazy() 配合 import() 函数,实现组件的代码分割,让路由组件被单独打包成不同的文件。
jsx
import { lazy } from 'react';
// 动态导入组件,只有访问该路由时才加载代码
const Login = lazy(() => import('@/pages/Login'));
const Home = lazy(() => import('@/pages/Home'));
2. 使用 <Suspense> 包裹路由,指定加载时的 fallback
<Suspense> 组件可以在路由组件加载完成前,显示一个自定义的 loading 界面,避免页面空白。
jsx
import { Suspense } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
// fallback 就是加载过程中显示的内容
<Suspense fallback={<h1>loading......</h1>}>
<Switch>
<Route path="/login" component={Login} />
<Route path="/home" component={Home} />
<Redirect to="/login" />
</Switch>
</Suspense>
三十七、React Hooks 核心知识点
一、React Hook 基础概念
- 定义:Hook 是 React 16.8.0 版本新增的特性 / 新语法。
- 作用 :可以让你在函数组件 中使用
state以及其他的 React 特性,不再依赖类组件。
二、三个常用的 Hook
- State Hook :
React.useState() - Effect Hook :
React.useEffect() - Ref Hook :
React.useRef()
三、State Hook(useState)
-
作用 :让函数组件也可以有
state状态,并进行状态数据的读写操作。 -
语法:
jsxconst [xxx, setXxx] = React.useState(initValue) -
参数与返回值说明:
- 参数:第一次初始化时指定的值,会在内部缓存起来。
- 返回值:包含 2 个元素的数组,第 1 个为当前状态值,第 2 个为更新状态值的函数。
-
更新状态的两种写法:
-
写法一:
setXxx(newValue)直接传入非函数值,会用新值覆盖原状态。
-
写法二:
setXxx(value => newValue)传入一个函数,接收原本的状态值,返回新的状态值,内部会用新值覆盖原状态。
-
示例代码
jsx
function Demo(){
console.log('Demo');
// 定义状态count和更新函数setCount,初始值为0
const [count, setCount] = React.useState(0)
// 定义状态name和更新函数setName,初始值为'tom'
const [name, setName] = React.useState('tom')
// 增加count的回调
function add(){
// 依赖原状态更新时,推荐使用函数式写法
setCount(count => count + 1)
}
// 修改name的回调
function changeName(){
// 不依赖原状态,直接传入新值即可
setName('jack')
}
return (
<div>
<h2>当前求和为:{count}</h2>
<h2>我的名字是:{name}</h2>
<button onClick={add}>点我+1</button>
<button onClick={changeName}>点我改名</button>
</div>
)
}
export default Demo
四、Effect Hook(useEffect)
-
作用:可以让你在函数组件中执行副作用操作,常用于模拟类组件中的生命周期钩子。
-
常见的副作用操作:
- 发
ajax请求获取数据 - 设置订阅 / 启动定时器
- 手动更改真实 DOM
- 发
-
基础语法:
jsuseEffect(() => { // 1. 副作用执行区:在此可以执行任何带副作用操作 return () => { // 2. 清理函数:在组件卸载前/副作用重新执行前执行 // 用于收尾工作,比如清除定时器、取消订阅等 } }, [stateValue]) // 3. 依赖数组
依赖数组的不同用法
| 依赖数组形式 | 执行时机 | 对应类组件生命周期 |
|---|---|---|
| 不写依赖数组 | 每次组件渲染后都执行 | componentDidMount + componentDidUpdate |
空数组 [] |
仅在组件第一次渲染后执行一次 | componentDidMount |
包含状态值 [stateValue] |
首次渲染后执行,且当 stateValue 变化时再次执行 |
componentDidMount + componentDidUpdate(仅监听指定状态) |
4、与类组件生命周期的对应关系
useEffect 可以看作以下三个生命周期钩子的组合:
componentDidMount:组件挂载后执行(通过空依赖数组实现)componentDidUpdate:组件更新后执行(通过依赖数组监听状态变化实现)componentWillUnmount:组件卸载前执行(通过返回的清理函数实现)
五、React Ref Hook
一、基础定义
useRef 是 React 提供的 Ref Hook,用于在函数组件中创建一个可变的 ref 对象,可以用来存储 / 查找组件内的 DOM 标签或任意其他数据。
二、语法
jsx
const refContainer = useRef(initialValue);
useRef返回一个可变的 ref 对象,其.current属性被初始化为传入的initialValue。- 该对象在组件的整个生命周期内保持不变,每次渲染都会返回同一个对象引用。
三、核心作用
-
保存 / 获取 DOM 元素
功能上与类组件的
React.createRef()完全一致,可以直接绑定到元素上,用于获取其 DOM 实例。jsxfunction Demo() { const inputRef = useRef(null); function handleClick() { // 通过 ref.current 获取 DOM 元素 inputRef.current.focus(); } return ( <div> <input ref={inputRef} type="text" /> <button onClick={handleClick}>聚焦输入框</button> </div> ); } -
存储任意可变数据
useRef不仅可以存 DOM,还可以用来保存组件中不参与渲染的可变数据,比如定时器 ID、上一次的状态值等。jsxfunction Demo() { const timerRef = useRef(null); useEffect(() => { timerRef.current = setInterval(() => { console.log("定时器运行中"); }, 1000); return () => { // 组件卸载时清除定时器 clearInterval(timerRef.current); }; }, []); }
四、关键特性
- 组件重新渲染时,
useRef返回的对象不会改变。 - 修改
.current属性的值不会触发组件重新渲染 ,这是它和useState的核心区别。 - 可以用来保存上一次的状态值,解决闭包陷阱问题。
三十八、React Fragment 核心知识点
Fragment 是 React 提供的一个内置组件,专门用来解决组件必须返回单个根节点的限制,又不会额外生成 DOM 节点。
一、为什么需要 Fragment?
在 React 中,组件的 render 函数(或函数组件的返回值)必须只能返回单个根节点。
如果我们直接写多个并列元素,会报错:
jsx
// ❌ 错误写法:返回了多个根节点
function App() {
return (
<h1>标题</h1>
<p>段落</p>
);
}
以前我们常用 <div> 包裹,但这会在 DOM 中多生成一层不必要的 <div>,可能导致样式问题或 DOM 结构冗余。Fragment 就是为了解决这个问题而生的。
二、两种基本用法
1. 完整写法(推荐在复杂场景使用)
jsx
import { Fragment } from 'react';
function App() {
return (
<Fragment>
<h1>标题</h1>
<p>段落</p>
</Fragment>
);
}
渲染结果:不会生成额外的 DOM 节点,直接输出:
<h1>标题</h1>
<p>段落</p>
2. 短语法(最常用,面试常考)
React 提供了更简洁的空标签 <> 作为 Fragment 的简写形式:
jsx
function App() {
return (
<>
<h1>标题</h1>
<p>段落</p>
</>
);
}
效果和完整写法完全一致,也是开发中最常用的方式。
三、Fragment 的核心特性
-
不渲染额外 DOM:它只是一个逻辑容器,不会在页面上生成任何真实的 HTML 标签,避免了无意义的节点嵌套。
-
支持
key属性:-
完整写法
<Fragment>可以接收key属性,用于列表渲染场景:jsxfunction List({ items }) { return ( <dl> {items.map(item => ( <Fragment key={item.id}> <dt>{item.term}</dt> <dd>{item.description}</dd> </Fragment> ))} </dl> ); } -
注意:短语法
<>不支持key或其他属性 ,需要传key时必须用完整写法。
-
-
可以接收子节点 :和普通组件一样,
Fragment可以包含多个子元素,实现多根节点返回。
四、常见使用场景
- 组件需要返回多个并列元素(如列表项、表格的单元格)
- 不想在 DOM 中引入额外的包裹节点(避免影响 CSS 样式或选择器)
- 列表渲染中,需要为多个元素添加同一个
key属性 (如<dl>中的<dt>和<dd>配对)
五、面试高频考点
-
Fragment和div的区别:div会渲染真实的 DOM 节点,而Fragment不会,仅作为逻辑容器。Fragment不会影响页面结构和样式,而多余的div可能导致布局问题。
-
短语法
<>和完整写法<Fragment>的区别:- 短语法更简洁,但不支持
key和其他属性。 - 完整写法支持
key,适用于列表渲染场景。
- 短语法更简洁,但不支持
三十九、context
一、什么时候用 Context?
- 多个层级的组件需要共享数据
- 比如:主题、语言、用户信息、全局配置
- 不想用 Redux 又想跨层传值时
一句话:爷孙、多层组件通信,用 Context 最方便
二、三个核心 API
1. React.createContext()
创建一个上下文对象。
js
const MyContext = React.createContext(defaultValue)
2. <MyContext.Provider>
数据提供者,用来提供数据。
jsx
<MyContext.Provider value={共享的数据}>
{/* 所有子组件都能拿到 value */}
</MyContext.Provider>
3. <MyContext.Consumer> / useContext
数据消费者,用来读取数据。
- 类组件用
Consumer - 函数组件用
useContext钩子
三、函数组件用法(最常用)
1. 创建 Context
jsx
// ThemeContext.js
import { createContext } from 'react'
const ThemeContext = createContext()
export default ThemeContext
2. 顶层提供数据
jsx
import ThemeContext from './ThemeContext'
function App() {
return (
<ThemeContext.Provider value={{ color: 'red' }}>
<Child />
</ThemeContext.Provider>
)
}
3. 后代组件使用数据
jsx
import { useContext } from 'react'
import ThemeContext from './ThemeContext'
function Child() {
const theme = useContext(ThemeContext)
return <div style={{ color: theme.color }}>文字</div>
}
四、类组件用法
jsx
class Child extends React.Component {
static contextType = ThemeContext
render() {
return <div>{this.context.color}</div>
}
}
或者用 Consumer:
jsx
<ThemeContext.Consumer>
{value => <div>{value.color}</div>}
</ThemeContext.Consumer>
四十、pureComponent

四十一、render props


四十二、ErrorBoundary
