react-redux useSelector钩子 学习样例 + 详细解析
(一)react-redux useSelector 学习样例 + 详细解析
创建一个新项目,将依赖正确安装:
npx create-react-app my-redux-app cd my-redux-app # 安装 Redux 和 React-Redux npm install redux react-redux # 安装 ajv npm install ajv # 安装最新的 react-scripts npm install react-scripts@latest npm install antd
my-redux-app/
├── public/
│ └── index.html
├── src/
│ ├── actions/
│ │ └── index.js
│ ├── components/
│ │ └── GiftSelector.js
│ ├── reducers/
│ │ └── index.js
│ ├── store/
│ │ └── index.js
│ ├── App.js
│ └── index.js
└── package.json
package.json
{
"name": "my-redux-app",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.4",
"redux": "^4.1.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
}
1.src/actions/index.js
export const SET_GIFT_ITEMS = 'SET_GIFT_ITEMS';
export const setGiftItems = (giftItems) => ({
type: SET_GIFT_ITEMS,
payload: giftItems,
});
2.src/reducers/index.js
import { combineReducers } from 'redux';
import { SET_GIFT_ITEMS } from '../actions';
const initialSettingInfo = {
giftOptionIndex: 0,
giftItems: [],
};
const settingInfo = (state = initialSettingInfo, action) => {
switch (action.type) {
case SET_GIFT_ITEMS:
return {
...state,
giftItems: action.payload,
};
default:
return state;
}
};
const rootReducer = combineReducers({
settingInfo,
});
export default rootReducer;
3.src/store/index.js
import { createStore } from 'redux';
import rootReducer from '../reducers';
const store = createStore(rootReducer);
export default store;
4.src/components/GiftSelector.js
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Select, Button } from 'antd';
import { setGiftItems } from '../actions';
const { Option } = Select;
const giftList = [
{ giftId: 1, giftName: '礼物1' },
{ giftId: 2, giftName: '礼物2' },
{ giftId: 3, giftName: '礼物3' },
];
const GiftSelector = () => {
const [selectedGiftId, setSelectedGiftId] = useState(null);
const dispatch = useDispatch();
const giftItems = useSelector((state) => state.settingInfo.giftItems);
const handleChange = (value) => {
setSelectedGiftId(value);
};
const handleAddGift = () => {
if (selectedGiftId) {
const selectedGift = giftList.find((gift) => gift.giftId === selectedGiftId);
const newGiftItems = [...giftItems, selectedGift];
dispatch(setGiftItems(newGiftItems));
}
};
return (
<div>
<Select style={{ width: 200 }} onChange={handleChange} placeholder="选择一个礼物">
{giftList.map((gift) => (
<Option key={gift.giftId} value={gift.giftId}>
{gift.giftName}
</Option>
))}
</Select>
<Button type="primary" onClick={handleAddGift} style={{ marginLeft: 10 }}>
添加
</Button>
<div>
<h3>已添加的礼物:</h3>
{giftItems.map((gift) => (
<div key={gift.giftId}>{gift.giftName}</div>
))}
</div>
</div>
);
};
export default GiftSelector;
5.src/App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import GiftSelector from './components/GiftSelector';
import 'antd/dist/antd.css';
const App = () => {
return (
<Provider store={store}>
<GiftSelector />
</Provider>
);
};
export default App;
6.src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
运行项目
npm start
功能描述
GiftSelector 组件:
- 使用
Select
组件展示礼物列表。- 使用
Button
组件添加选中的礼物。- 添加的礼物展示在下方。
状态管理:
- 使用 Redux 管理
giftItems
状态。- 动作
setGiftItems
用于更新giftItems
。这个项目展示了如何使用
antd
组件结合 Redux 来实现礼物选择和添加功能。
>>>>作用
(1)获取 Redux 状态:
useSelector
是 React-Redux 库中的一个钩子函数,用于从 Redux 状态树中提取数据。
(2)通过 Selector 提取特定状态:
useSelector
接受一个回调函数,该回调函数会被调用并传递 Redux 状态树作为参数。- 在这个回调函数中,你可以从状态树中选择你需要的部分状态。
(3)具体实现:
(state) => state.settingInfo.giftItems
是传递给useSelector
的回调函数。state
参数代表整个 Redux 状态树。state.settingInfo
获取settingInfo
这个 reducer 管理的状态部分。state.settingInfo.giftItems
获取settingInfo
中的giftItems
数组。
(4)结果:
- 返回的
giftItems
就是settingInfo
中的giftItems
数组,即当前已经添加的礼物列表。 - 当
settingInfo.giftItems
发生变化时,React 组件会重新渲染以反映最新状态。
让我们详细说明一下数据更新的流程。以我们的 GiftSelector 示例为例,具体流程包括以下步骤:
1. 初始状态
在 Redux 中,giftItems 的初始状态为空数组。
const initialState = {
giftOptionIndex: 0,
giftItems: [],
};
2. 用户选择礼物并点击添加按钮
用户通过 Ant Design Select
组件选择一个礼物,并点击 "添加" 按钮触发操作。
3. 触发 Redux Action
点击 "添加" 按钮时,触发 handleAddGift
函数,这会分发一个 setGiftItems
action 来更新状态。
const handleAddGift = () => {
if (selectedGiftId) {
const selectedGift = giftList.find((gift) => gift.giftId === selectedGiftId);
const newGiftItems = [...giftItems, selectedGift];
dispatch(setGiftItems(newGiftItems));
}
};
4. Action 创建器
setGiftItems
action 创建器返回一个 action 对象。
// src/actions/index.js
export const SET_GIFT_ITEMS = 'SET_GIFT_ITEMS';
export const setGiftItems = (giftItems) => ({
type: SET_GIFT_ITEMS,
payload: giftItems,
});
5. Redux Reducer 处理 Action
Redux store 接收到 SET_GIFT_ITEMS
action 后,reducer 处理这个 action 并返回更新的状态。
// src/reducers/index.js
const initialSettingInfo = {
giftOptionIndex: 0,
giftItems: [],
};
const settingInfo = (state = initialSettingInfo, action) => {
switch (action.type) {
case SET_GIFT_ITEMS:
return {
...state,
giftItems: action.payload,
};
default:
return state;
}
};
6. Store 更新状态
Redux store 根据 reducer 的返回值更新 settingInfo.giftItems
状态。
7. React 组件重新渲染
由于 useSelector
钩子将 giftItems
状态映射到组件中,当 Redux 状态更新时,组件会自动重新渲染以反映最新的状态。
const giftItems = useSelector((state) => state.settingInfo.giftItems);
示例流程
让我们具体展示一次用户操作和状态更新的流程:
(1)初始状态:
{
giftOptionIndex: 0,
giftItems: [],
}
(2)用户选择礼物:
- 用户选择
giftId: 1
的礼物(礼物1)。 selectedGiftId
更新为 1。
(3)点击 "添加" 按钮:
-
调用
handleAddGift
函数。 -
newGiftItems
计算为[{ giftId: 1, giftName: '礼物1' }]
。 -
分发
setGiftItems(newGiftItems)
:
(4)Reducer 处理 Action:
-
接收到
SET_GIFT_ITEMS
action。 -
返回更新后的状态:
{
giftOptionIndex: 0,
giftItems: [{ giftId: 1, giftName: '礼物1' }],
}
(5)组件重新渲染:
-
GiftSelector
组件由于giftItems
状态更新而重新渲染。 -
新状态
giftItems
映射到组件,UI 显示已添加的礼物:
<div key={gift.giftId}>{gift.giftName}</div>
这就是完整的数据更新流程:
- 用户操作触发事件,事件分发 action,reducer 处理 action 并返回新状态,store 更新状态,React 组件重新渲染以反映新状态。
总结
- 用户选择礼物。
- 点击按钮分发 action。
- Reducer 接收 action 并更新状态。
- Redux store 更新状态。
useSelector
获取最新状态,组件重新渲染 UI。
(二)useSelector
useSelector
是 React-Redux 提供的一个钩子,用于从 Redux 的状态树中提取部分数据。
基本概念
useSelector
的主要作用是:
- 从 Redux 状态树中选择(或提取)数据。
- 在选中的数据发生变化时自动重新渲染组件。
例子和解释
假设我们在 Redux 状态中存储了一些礼物信息,并且希望在组件中获取和显示这些礼物信息。
Redux 状态结构
首先,假设我们的 Redux 状态结构如下:
const initialState = {
settingInfo: {
giftOptionIndex: 0,
giftItems: [], // 这里存放礼物数组
},
};
使用 useSelector 钩子从 Redux 状态中获取数据
在组件中,我们使用 useSelector
钩子从 Redux 状态中提取 giftItems
数据:
import React from 'react';
import { useSelector } from 'react-redux';
const GiftList = () => {
// 使用 useSelector 提取 giftItems
const giftItems = useSelector((state) => state.settingInfo.giftItems);
return (
<div>
<h3>已添加的礼物:</h3>
{giftItems.map((gift) => (
<div key={gift.giftId}>{gift.giftName}</div>
))}
</div>
);
};
export default GiftList;
详细步骤
- 引入 useSelector: 首先确保从
react-redux
引入了useSelector
:
import { useSelector } from 'react-redux';
- 定义 Selector 回调函数:
useSelector
接受一个回调函数,这个回调函数有一个参数 state
,代表整个 Redux 状态树。
const giftItems = useSelector((state) => state.settingInfo.giftItems);
上面的代码意思是:
- 从 Redux 状态树中选择
state.settingInfo.giftItems
这个部分。 giftItems
会得到state.settingInfo.giftItems
的值。
输出提取的数据: 在 JSX 中,可以使用 giftItems
来输出数据,例如:
{giftItems.map((gift) => (
<div key={gift.giftId}>{gift.giftName}</div>
))}
工作原理
-
获取当前状态:
useSelector
从 Redux store 中获取当前状态(或数据)。 -
订阅状态变化: 当所选择的状态部分发生变化时,
useSelector
会让组件重新渲染,以反映最新状态。 -
返回选中的状态:
giftItems
存储了最新的被选中的状态部分的数据。
在这个完整的例子中,useSelector
钩子用于从 Redux 状态树中提取 settingInfo.giftItems
。当 giftItems
发生变化时,组件会自动重新渲染并显示最新的礼物列表。