(一)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@latestnpm 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 提取 giftItemsconst 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
发生变化时,组件会自动重新渲染并显示最新的礼物列表。