React
流行的UI组件库
创建项目
- npm create vite antd-demo
安装antd
- npm install antd --save
redux
- 官网地址
- 安装: npm i redux
- redux是一个专门用于做状态管理的js库
- 作用:集中式管理react应用中多个组件共享的状态
- redux的reducer函数必须是一个纯函数
纯函数
- 不得改写参数数据
- 不会产生任何副作用,例如网络请求,输入和输出设备
- 不能调用Date.now()或者Math.random等不纯的方法
什么情况下需要使用redux
- 某个组件的状态,需要让其它组件可以随时拿到(共享)
- 一个组件需要改变另一个组的状态(通信)

三个核心概念
action
- 动作的对象, 包含2个属性,
- type:标识属性,值为字符串,唯一,必要属性
- data:数据属性,值类型任意,可选属性
- 类似{type:'ADD_STUDENT',data:{name:"乞力马扎罗",age:18}}
Store
- 将state,action,reducer联系在一起的对象
reducer
- 用于初始化状态,加工状态
- 加工的时候,根据旧的state和action,产生新的state的纯函数
Redux-V5版本
创建store
redux文件下
- store.js
javascript
import { createStore } from 'redux'; // 如果你用的是官方 redux,否则用之前自定义的 createStore
import { countReducer } from './count';
// 创建 store
const store = createStore(countReducer);
export default store;
对应功能的状态管理
- count.js
javascript
export const countFunAdd = (data) => {
return {
type: 'COUNT_ADD',
data,
}
}
export const countFunLess = (data) => {
return {
type: 'COUNT_LESS',
data,
}
}
// 定义 reducer
const initialState = {
count: 0,
name: '乞力马扎罗',
}
export const countReducer = (state = initialState, action) => {
const { type, data } = action
console.log(state);
switch (type) {
case 'COUNT_ADD':
return {
...state,
count: state.count + data,
}
case 'COUNT_LESS':
return {
...state,
count: state.count - data,
}
default:
return state
}
}
页面使用
javascript
import React from 'react'
import { Button, Flex } from 'antd'
import { useState, useRef } from 'react'
import store from '../../redux/store'
import { countFunAdd, countFunLess } from '../../redux/count'
function Count() {
const data = store.getState()
return (
<>
<h1>用户数据:{data.name},{data.count}</h1>
<button onClick={() => store.dispatch(countFunAdd(1))}>加</button>
<button onClick={() => store.dispatch(countFunAdd(-1))}>减</button>
</>
)
}
export default Count
实时监听
- main.jsx
javascript
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import store from './redux/store'
// 1. 只创建一次 Root 实例(核心优化)
const root = createRoot(document.getElementById('root'));
// 2. 定义渲染函数(复用)
function renderApp() {
root.render(
<StrictMode>
<App />
</StrictMode>
);
}
// 3. 初始渲染(必加,保证页面首次加载有内容)
renderApp();
// 4. 监听状态变化,仅重新渲染(复用已创建的 root 实例)
store.subscribe(renderApp);
Redux-v5版本(异步)
- npm i redux-thunk,并配置在store
- 异步action,就是指action的值为函数
- 引入redux-thunk,用于支持异步action,让它当中间件和Store沟通,让只支持对象属性的Store现在支持函数
创建store.js
- 引入redux-thunk
javascript
import { createStore,applyMiddleware } from 'redux' // 如果你用的是官方 redux,否则用之前自定义的 createStore
import { countReducer} from './count'
// 引入redux-thunk,用于支持异步action
import {thunk} from 'redux-thunk'
// 创建 store
const store = createStore(countReducer,applyMiddleware(thunk))
export default store
编写异步action
- 异步action中一般都会调用同步action
- 异步中直接使用dispatch
javascript
import store from './store'
export const countFunAdd = (data) => {
return {
type: 'COUNT_ADD',
data,
}
}
// 异步action , 就是指action的值是函数,异步action中一般都会调用同步action
export const countFunAsynAdd = (data) => {
return (dispatch) => {
setTimeout(() => {
dispatch(countFunAdd(data))
}, 2000)
}
}
export const countFunLess = (data) => {
return {
type: 'COUNT_LESS',
data,
}
}
// 定义 reducer
const initialState = {
count: 0,
name: '乞力马扎罗',
}
export const countReducer = (state = initialState, action) => {
const { type, data } = action
console.log(state)
switch (type) {
case 'COUNT_ADD':
return {
...state,
count: state.count + data,
}
case 'COUNT_LESS':
return {
...state,
count: state.count - data,
}
default:
return state
}
}
页面实现
javascript
import React from 'react'
import { Button, Flex } from 'antd'
import { useState, useRef } from 'react'
import store from '../../redux/store'
import { countFunAdd, countFunLess,countFunAsynAdd} from '../../redux/count'
function Count() {
const data = store.getState()
return (
<>
<h1>用户数据:{data.name},{data.count}</h1>
<button onClick={() => store.dispatch(countFunAdd(1))}>加</button>
<button onClick={() => store.dispatch(countFunAsynAdd(1))}>异步加</button>
<button onClick={() => store.dispatch(countFunAdd(-1))}>减</button>
</>
)
}
export default Count
实时监听
- main.jsx
javascript
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import store from './redux/index'
// 1. 只创建一次 Root 实例(核心优化)
const root = createRoot(document.getElementById('root'));
// 2. 定义渲染函数(复用)
function renderApp() {
root.render(
<StrictMode>
<App />
</StrictMode>
);
}
// 3. 初始渲染(必加,保证页面首次加载有内容)
renderApp();
// 4. 监听状态变化,仅重新渲染(复用已创建的 root 实例)
store.subscribe(renderApp);
react-redux模型图
- UI组件,不能使用任何redux的api,只负责页面的呈现和交互
- 容器组件,负责和redux通信,将结果交给UI组件,通过react-redux的connect函数创建一个容器组件
- 注意:容器组件中的store是靠父组件的props传进去的,而不是在容器组件中直接引入的
- 注意:redux需要通过subscribe监听变化,而react-redux通过connect()()已经实现动态监听,无需subscribe
javascript
// 监听状态变化,仅重新渲染(复用已创建的 root 实例)
store.subscribe(renderApp);

文件目录

封装的store和状态数据
- redux文件下的index.js
javascript
import { createStore,applyMiddleware } from 'redux' // 如果你用的是官方 redux,否则用之前自定义的 createStore
import { countReducer} from './count'
// 引入redux-thunk,用于支持异步action
import {thunk} from 'redux-thunk'
// 创建 store
const store = createStore(countReducer,applyMiddleware(thunk))
export default store
- redux文件下的count.js
javascript
export const countFunAdd = (data) => {
return {
type: 'COUNT_ADD',
data,
}
}
// 异步action , 就是指action的值是函数,异步action中一般都会调用同步action
export const countFunAsynAdd = (data) => {
return (dispatch) => {
setTimeout(() => {
dispatch(countFunAdd(data))
}, 2000)
}
}
export const countFunLess = (data) => {
return {
type: 'COUNT_LESS',
data,
}
}
// 定义 reducer
const initialState = {
count: 0,
name: '乞力马扎罗',
}
export const countReducer = (state = initialState, action) => {
const { type, data } = action
switch (type) {
case 'COUNT_ADD':
return {
...state,
count: state.count + data,
}
case 'COUNT_LESS':
return {
...state,
count: state.count - data,
}
default:
return state
}
}
容器组件
- 新建容器组件
- 和UI组件建立联系
javascript
// 容器组件
// 引入Count的UI组件
import CountUI from '../../components/Count'
// 引入connect用于链接UI组件与redux
import { connect } from 'react-redux'
// 引入修改状态数据的封装方法
import { countFunAdd } from '../../redux/count'
//connect传递的函数,第一个函数是state
//a函数返回的对象,这里获取状态state
function a(state) {
const { name, count } = state
return state
}
// onnect传递的函数,第二个函数是dispatch
// b 函数的参数只有 dispatch,没有 state
function b(dispatch) {
return {
getCount: (params) => {
dispatch(countFunAdd(params))
},
}
}
// 使用connect()()创建并暴露一个Count的容器组件
// connect 是 React-Redux 提供的高阶函数,它的完整参数签名 connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)
// 所以,这里的a,b参数名叫mapStateToProps,mapDispatchToProps更贴切
// CountUI是链接了UI组件
export default connect(a, b)(CountUI)
- 简写:

UI组件
javascript
import React from 'react'
import { Button, Flex } from 'antd'
import { useRef } from 'react'
function Count(props) {
// UI组件props调用,UI组件里不会出来store,容器组件进行交互
const { name, count, getName, getCount } = props
function handleAdd() {
getCount(1)
}
return (
<>
<h1>
用户数据:{name},{count}
</h1>
<button
onClick={handleAdd}
>
加
</button>
<button onClick={() => {}}>异步加</button>
<button onClick={() => {}}>减</button>
</>
)
}
export default Count
main.jsx
- 组件顶层,传入store
- 让react-redux和redux建立联系
javascript
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
// 步骤1 Provider包裹
import { Provider } from 'react-redux'
// 步骤2,传入store,让react-redux和redux建立联系
import store from './redux/index.js'
createRoot(document.getElementById('root')).render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>
)
页面使用
javascript
import React from 'react'
import { Button, Flex } from 'antd'
import { useRef } from 'react'
function Count(props) {
// UI组件props调用,UI组件里不会出来store,容器组件进行交互
const { name, count, getName, getCount } = props
function handleAdd() {
getCount(1)
}
return (
<>
<h1>
用户数据:{name},{count}
</h1>
<button
onClick={handleAdd}
>
加
</button>
<button onClick={() => {}}>异步加</button>
<button onClick={() => {}}>减</button>
</>
)
}
export default Count
ReduxToolkit(简称RTK),新版本
javascript
// 创建一个切片
import { createSlice } from '@reduxjs/toolkit'
// 比较正统的正规的写法
const userSlice = createSlice({
name: '乞力马扎罗',
age: '18',
reducers: {
//修改名称
setName(state, action) {
const { type, payload } = action
return {
...state,
name: action.payload,
}
},
},
})
export default userSlice

- 前置安装:npm i react-redux @reduxjs/toolkit
- 优点:
- 允许我们在reducers写"可变"逻辑
- 当然,这个也并不是真正的改变状态值,因为它使用了Immer库
- 可以检测到"草稿状态"的变化并且基于这些变化生成全新的
- 类似下面直接修改state,并没有写新的去return覆盖
创建切片
- redux文件下新建
- user.js(用户数据)
- good.js(商品数据)
用户状态数据
javascript
//一个项目中有不同的状态数据,根据状态的不同,创建不同的切片,比如用户数据,商品数据
import { createSlice } from '@reduxjs/toolkit'
const userSlice = createSlice({
// 切片名称
name: 'user-slice',
// 初始数据
initialState: { name: '乞力马扎罗', age: '18' },
// 操作数据的方法
reducers: {
//修改名称
setName(state, action) {
state.name = action.payload
},
//修改age
setName(state, action) {
state.age = action.payload
},
},
})
export default userSlice
商品状态数据
javascript
import { createSlice } from '@reduxjs/toolkit'
const goodSlice = createSlice({
name: 'good-slice',
initialState: {
name: '衣服',
price: '200',
},
reducers: {
setName(state, action) {
state.name = action.payload
},
setPrice(state, action) {
state.price = action.payload
},
},
})
合并切片
- redux文件下新建index.js(合并切片数据)
javascript
// 合并切片js
import { configureStore } from '@reduxjs/toolkit'
import goodSlice from './good'
import userSlice from './user'
const store = configureStore({
reducer: {
user: userSlice.reducer,
good: goodSlice.reducer,
},
})
// 因为setName多个切片都有,实际调用的时候,切片名也会调用{type:'goods-slice/setName',payload:'罗曼蒂克'}
export default store
项目配置
javascript
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
//步骤1 Provider包裹
import { Provider } from 'react-redux'
// 步骤2,传入store
import store from './redux/store.js'
createRoot(document.getElementById('root')).render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>
)
项目使用
- useSelector 从 store 中读取数据
- useDispatch 获取 dispatch 函数,并根据需要 dispatch actions
javascript
import React from 'react'
import { Button, Flex } from 'antd'
import { useState, useRef } from 'react'
import { useSelector, useDispatch } from 'react-redux'
function Count() {
const user = useSelector((state) => state.user)
const dispatch = useDispatch()
return (
<>
<h1>用户数据:{JSON.stringify(user)}</h1>
<button
onClick={() =>
dispatch({ type: 'user-slice/setName', payload: '罗曼蒂克' })
}
>
点击修改数据
</button>
</>
)
}
export default Count
简约写法
javascript
import React from 'react'
import { Button, Flex } from 'antd'
import { useState, useRef } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import userSlice from '../../redux/user'
function Count() {
const user = useSelector((state) => state.user)
const dispatch = useDispatch()
const {setName} = userSlice.actions
return (
<>
<h1>用户数据:{JSON.stringify(user)}</h1>
{/* 生成 action + 派发 action */}
<button
onClick={() =>
dispatch(setName('罗曼蒂克'))
}
>
点击修改数据
</button>
</>
)
}
export default Count
Provider组件
- 本质是一个 React 高阶组件,基于 React 的 Context(上下文) 实现
- 核心作用:将 Redux 的 store 注入到整个 React 组件树中,让所有被 Provider 包裹的子组件(无论层级多深),都能通过 connect 或 useSelector/useDispatch Hooks 访问到 store,无需手动层层传递 store 作为 props
- 一个应用只需要一个 Provider:通常包裹在根组件外层即可,无需多层嵌套;
- 支持传入多个 store?不推荐:如果有多个 reducer,建议用 combineReducers 合并成一个 store,而非多个 Provide
- React-Redux v7+ 推荐 Hooks:除了 connect,也可以用 useSelector/useDispatch 直接获取状态 / 触发 action,底层依然依赖 Provider 提供的 Context
- 总结:
- Provider 的核心作用是全局注入 Redux 的 store,基于 React Context 实现
- 解决了 "手动层层传递 store props" 的痛点,让所有子组件能便捷访问 store
- 使用时只需在根组件外层包裹一次,传入 store 属性即可
未使用的版本,想要传递store
- 你需要把 store 作为 props 手动传给每一层组件(比如父→子→孙),层级深了会非常繁琐
javascript
import React from 'react'
import Count from "./containers/Count";
import store from './redux/index'
const App = () => {
return (
<div>
{/* 如果不用Provider,就需要给对应的组件传上store */}
<Count store={store}></Count>
<Count store={store}></Count>
<Count store={store}></Count>
<Count store={store}></Count>
<Count store={store}></Count>
<Count store={store}></Count>
</div>
)
}
export default App
使用Provider 的话
javascript
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
// 步骤1 Provider包裹
import { Provider } from 'react-redux'
// 步骤2,传入store,让react-redux和redux建立联系
import store from './redux/index.js'
createRoot(document.getElementById('root')).render(
<StrictMode>
<Provider store={store}>
<App />
</Provider>
</StrictMode>
)
个人总结
- 步骤-1:创建store
- 步骤0:根组件Provider包裹传入store
- 步骤1:创建页面组件
- 步骤2:创建动作对象action
- 步骤3:创建reducer,分发action
- 步骤4:页面使用redux


传统模式
javascript
import React from 'react'
import './index.css'
import { Button, Flex } from 'antd'
// 容器组件
import { connect } from 'react-redux'
// 引入修改状态数据的封装方法
import { countFunAdd } from '../../redux/count'
// 优化mapStateToProps:仅返回组件需要的状态,避免冗余
function mapStateToProps(state) {
// 只提取 countReduxs 和 personReduxs (组件实际用到的状态)
return {
countReduxs: state.countReduxs,
personReduxs: state.personReduxs
}
}
// 优化mapDispatchToProps:保持原有逻辑,函数名语义化(原函数b改为mapDispatchToProps)
function mapDispatchToProps(dispatch) {
return {
getCount: (params) => {
dispatch(countFunAdd(params))
},
}
}
function Count(props) {
console.log(props)
// 移除不存在的 getName 解构,仅保留有效属性
const { name, count } = props.countReduxs
const { getCount } = props
const { personList } = props.personReduxs
function handleAdd() {
getCount(1)
}
return (
<div className="Count">
<h4>
用户数据:{name},{count}
</h4>
{/* 统一使用 antd Button 组件,替换原生 button */}
<Button onClick={handleAdd} type="primary">加1</Button>
<h4>
获取下面的person数据:
{/* 移除重复的 name/count 渲染,仅保留 personList 遍历 */}
{personList.map((user, index) => (
<div key={index} style={{ margin: '10px 0' }}>
用户名:{user.username},密码:{user.password}
</div>
))}
</h4>
</div>
)
}
// 容器组件导出:使用语义化的映射函数名
export default connect(mapStateToProps, mapDispatchToProps)(Count)
Hooks模式
javascript
import React from 'react'
import { Button, Form, Input } from 'antd'
// 1. 引入Redux的useDispatch钩子
import { useDispatch, useSelector } from 'react-redux'
import { personAction } from '../../redux/person'
import './index.css'
const App = () => {
// 2. 创建dispatch实例(必须在函数组件内部声明)
const dispatch = useDispatch()
const count = useSelector((state) => state.countReduxs.count)
// 3. 重构提交函数,通过dispatch分发action,关键:调用dispatch,把action对象分发到reducer
const onFinish = (values) => {
dispatch(personAction(values))
}
return (
<div className="Person">
<h4>获取上面组件的count:{count}</h4>
<Form
name="basic"
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
style={{ maxWidth: 600 }}
initialValues={{ remember: true }}
onFinish={onFinish}
autoComplete="off"
>
<Form.Item
label="Username"
name="username"
rules={[{ required: true, message: 'Please input your username!' }]}
>
<Input />
</Form.Item>
<Form.Item
label="Password"
name="password"
rules={[{ required: true, message: 'Please input your password!' }]}
>
<Input.Password />
</Form.Item>
<Form.Item label={null}>
<Button type="primary" htmlType="submit">
提交
</Button>
</Form.Item>
</Form>
</div>
)
}
export default App
redux开发者工具
- 谷歌商城导入:redux_dev_tools
- 配合插件使用,npm add redux-devtools-extension
- redux的store.js或者index.js引入

react 打包
- pnpm run build
- 打包完想看,就得放置服务器
- 想本地启服务器看打包完的dist或者build里的index.html
- 全局安装npm i serve -g
