React Native类组件用Redux报错,求完整使用示例
问题描述
我正在开发React Native项目,数据取自PHP数据库但加载速度过慢,尝试用Redux优化时出现以下错误:
err [Error: Invalid hook call. Hooks can only be called inside of the
body of a function component. This could happen for one of the
following reasons:
- React与渲染器(如React DOM)版本不匹配
- 违反了Hooks使用规则
- 应用中存在多个React副本 详情请查看相关文档获取调试和修复建议。]
相关代码:
let url = config.baseURL + 'home_data.php?user_id=' + user_id + '&APP_VERSION=1'; consolepro.consolelog('url', url); apifuntion .getApi(url) .then(obj => { if (obj.success == 'true') { consolepro.consolelog('homedataooooooooooooooooooooooooooooooooooooooooooooooooooo', obj); const dispatch = useDispatch(); const dataFromObj = useSelector(state => state.Reducers); consolepro.consolelog("dattttttttttttttttttttttttttttttttttttttttttttt", dataFromObj) dispatch(getDataMethod(obj)); check_notification_num = obj.check_notification_num; // (main_category_arr = obj.category_arr); config.content_arr = obj.content_arr; if (config.device_type == 'ios') { config.guest_status = obj.guest_status; } else { config.guest_status = false; } localStorage.setItemObject('user_arr', obj.user_details); this.setState({ category_arr: obj.category_arr, new_item: obj.all_product, }); } else { if ( obj.active_status == '0' || obj.msg[config.language] == msgTitle.usernotexit[config.language] ) { config.checkUserDeactivate(this.props.navigation); } else { msgProvider.alert( msgTitle.information[config.language], obj.msg[config.language], false, ); } return false; } }) .catch(err => { consolepro.consolelog('err', err); });
我熟悉函数组件中Redux的用法,但不知道如何在类组件中使用Redux,希望能得到一个简单完整的React Native类组件结合Redux的使用示例。
原因分析与解决方案
错误原因
你在类组件的异步回调(then方法内部)中使用了Redux Hooks(useDispatch、useSelector),而Hooks只能在函数组件的顶层作用域或自定义Hooks中调用,这直接违反了Hooks的使用规则,导致了该错误。类组件中不能使用Redux Hooks,需要通过react-redux提供的connect高阶函数连接Redux Store。
完整类组件结合Redux示例
1. 配置Redux Store
定义Action Types
// actions/types.js export const GET_DATA_SUCCESS = 'GET_DATA_SUCCESS';
定义Action Creators
// actions/dataActions.js import { GET_DATA_SUCCESS } from './types'; export const getDataSuccess = (data) => ({ type: GET_DATA_SUCCESS, payload: data });
定义Reducer
// reducers/dataReducer.js import { GET_DATA_SUCCESS } from '../actions/types'; const initialState = { homeData: null, loading: false }; const dataReducer = (state = initialState, action) => { switch(action.type) { case GET_DATA_SUCCESS: return { ...state, homeData: action.payload, loading: false }; default: return state; } }; export default dataReducer;
合并Reducer并创建Store
// store/index.js import { createStore, combineReducers } from 'redux'; import dataReducer from '../reducers/dataReducer'; const rootReducer = combineReducers({ data: dataReducer // 此key作为state中的命名空间 }); const store = createStore(rootReducer); export default store;
2. 在App入口注入Store
用Provider包裹根组件,让所有子组件可访问Store:
// App.js import React from 'react'; import { Provider } from 'react-redux'; import store from './store'; import HomeScreen from './screens/HomeScreen'; export default function App() { return ( <Provider store={store}> <HomeScreen /> </Provider> ); }
3. 类组件中使用Redux
通过connect连接组件与Redux:
// screens/HomeScreen.js import React, { Component } from 'react'; import { View, Text } from 'react-native'; import { connect } from 'react-redux'; import { getDataSuccess } from '../actions/dataActions'; import apifuntion from '../utils/api'; import config from '../config'; import consolepro from '../utils/consolepro'; class HomeScreen extends Component { state = { category_arr: [], new_item: [] }; componentDidMount() { this.fetchHomeData(); } fetchHomeData = () => { const user_id = '替换为实际用户ID'; let url = config.baseURL + 'home_data.php?user_id=' + user_id + '&APP_VERSION=1'; consolepro.consolelog('url', url); apifuntion .getApi(url) .then(obj => { if (obj.success == 'true') { consolepro.consolelog('homedata', obj); // 通过props中的dispatch触发action,将数据存入Redux this.props.dispatchGetData(obj); // 原有业务逻辑保留 check_notification_num = obj.check_notification_num; config.content_arr = obj.content_arr; config.guest_status = config.device_type === 'ios' ? obj.guest_status : false; localStorage.setItemObject('user_arr', obj.user_details); this.setState({ category_arr: obj.category_arr, new_item: obj.all_product, }); } else { if (obj.active_status == '0' || obj.msg[config.language] == msgTitle.usernotexit[config.language]) { config.checkUserDeactivate(this.props.navigation); } else { msgProvider.alert( msgTitle.information[config.language], obj.msg[config.language], false, ); } } }) .catch(err => { consolepro.consolelog('err', err); }); }; render() { // 从props中获取Redux中的数据 const { homeData } = this.props; return ( <View> <Text>Redux数据: {homeData ? JSON.stringify(homeData) : '加载中...'}</Text> {/* 其他UI渲染逻辑 */} </View> ); } } // 将Redux State映射到组件props const mapStateToProps = (state) => ({ homeData: state.data.homeData }); // 将Action Creators映射到组件props const mapDispatchToProps = (dispatch) => ({ dispatchGetData: (data) => dispatch(getDataSuccess(data)) }); // 连接组件与Redux export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);
关键说明
connect是类组件连接Redux的核心,通过mapStateToProps将Store中的数据映射到组件props,通过mapDispatchToProps将触发Action的方法映射到组件props。- 类组件中禁止使用任何React Hooks,所有Redux操作必须通过props完成。
- 异步请求可放在
componentDidMount等生命周期方法中,请求完成后通过props中的dispatch方法更新Store。
内容的提问来源于stack exchange,提问作者user19534405
相关产品推荐
相关产品推荐

