Firestore获取指定字段+React展示加油站品牌名的Redux问题排查
Firestore获取加油站品牌名并在React+Redux中展示问题解答
问题描述
我需要从Firestore数据库中获取所有加油站的品牌名,并在React组件中展示这些名称,但不确定应使用何种查询方式以及如何存储数据。我已尝试从Firestore获取所需信息并存入Redux,但未能成功。请问是否需要使用独立的reducers?
相关代码如下:
// Action Creators export const setStations = stations => ({ type: actionTypes.SET_STATIONS, stations }); export const setStationsNames = stationsNames => ({ type: actionTypes.SET_STATIONS_NAMES, stationsNames }); export const startSetStations = () => { return dispatch => { return db .collection('stations') .get() .then(snapshot => { const stations = []; const stationsNames = []; snapshot.docs.forEach(doc => { stations.push(doc.data()); stationsNames.push(doc.data().brand); }); dispatch(setStationsNames(stationsNames)); dispatch(setStations(stations)); }); }; }; // React组件渲染部分 {props.stations.map((station, i) => { return ( <li key={i} className="station"> <h3 className="station__text">{station.brand}</h3> </li> ); })} // Reducer export default (state = stationsReducerDefaultState, action) => { switch (action.type) { case actionTypes.SET_STATIONS: return action.stations; default: return state; } };
问题分析与解决方案
1. Firestore查询方式确认
你的基础查询逻辑是正确的:db.collection('stations').get()可以获取集合下所有文档,遍历快照提取brand字段的操作也没问题。如果想优化性能,建议只请求需要的brand字段,减少数据传输:
export const startSetStations = () => { return dispatch => { return db .collection('stations') .select('brand') // 仅请求brand字段,无需获取完整文档数据 .get() .then(snapshot => { const stationsNames = snapshot.docs.map(doc => doc.data().brand); // 如果仍需要完整数据,可以保留原逻辑,否则只获取品牌名即可 dispatch(setStationsNames(stationsNames)); }); }; };
2. Redux Redducer设计:是否需要独立reducer?
这取决于你的状态使用场景:
- 如果
stationsNames是独立使用的状态(比如单独用于下拉选择、搜索等),推荐创建独立的reducer来维护,避免单一reducer过于臃肿,同时让状态职责更清晰。 - 如果
stationsNames只是stations的衍生数据(仅用于从完整数据中提取品牌名展示),则无需单独存储,直接在组件中从props.stations推导即可,减少状态冗余:const stationBrands = props.stations.map(station => station.brand);
方案一:添加独立的stationsNames reducer
// stationsNamesReducer.js const initialState = []; export default (state = initialState, action) => { switch (action.type) { case actionTypes.SET_STATIONS_NAMES: return action.stationsNames; default: return state; } }; // 根reducer中合并 import { combineReducers } from 'redux'; import stationsReducer from './stationsReducer'; import stationsNamesReducer from './stationsNamesReducer'; export default combineReducers({ stations: stationsReducer, stationsNames: stationsNamesReducer });
方案二:在现有reducer中整合状态(适合关联紧密的场景)
如果希望把完整数据和品牌名放在同一个状态节点,可以修改现有reducer:
const initialState = { list: [], brands: [] }; export default (state = initialState, action) => { switch (action.type) { case actionTypes.SET_STATIONS: return { ...state, list: action.stations, brands: action.stations.map(station => station.brand) // 自动衍生品牌名 }; case actionTypes.SET_STATIONS_NAMES: return { ...state, brands: action.stationsNames }; default: return state; } };
3. React组件与Redux连接的关键注意事项
确保组件正确连接Redux并触发数据获取:
import { connect } from 'react-redux'; import { startSetStations } from '../actions/stations'; class StationsList extends React.Component { componentDidMount() { // 组件挂载时触发Firestore数据获取 this.props.startSetStations(); } render() { return ( <ul> {/* 方式一:从完整stations数据中提取品牌名展示 */} {this.props.stations.map((station, index) => ( // 优先使用Firestore文档的id作为key,比index更稳定 <li key={station.id || index} className="station"> <h3 className="station__text">{station.brand}</h3> </li> ))} {/* 方式二:直接使用独立维护的stationsNames状态 */} {/* {this.props.stationsNames.map((brand, index) => ( <li key={index} className="station"> <h3 className="station__text">{brand}</h3> </li> ))} */} </ul> ); } } // 映射Redux状态到组件props const mapStateToProps = (state) => ({ stations: state.stations.list, // 对应方案二的状态结构;方案一用state.stations stationsNames: state.stationsNames // 方案一需要映射这个状态 }); // 映射动作创建函数到组件props export default connect(mapStateToProps, { startSetStations })(StationsList);
4. 常见问题排查
- 检查Redux状态更新:使用Redux DevTools确认
SET_STATIONS和SET_STATIONS_NAMES动作是否触发,状态是否正确更新。 - Firestore权限验证:确保Firestore安全规则允许读取
stations集合(开发环境可临时设置allow read: if true;,生产环境需配置合理权限)。 - 组件生命周期触发:确认
startSetStations在组件挂载时被调用(类组件用componentDidMount,函数组件用useEffect(() => { ... }, []))。
内容的提问来源于stack exchange,提问作者Gvidas Pranauskas
相关产品推荐
相关产品推荐

