You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native:如何根据登录状态正确切换常量文件中的BaseUrl

React Native动态切换BaseUrl解决Invalid hook call错误

问题背景

我的React Native项目登录页面仅支持美国(+1)和印度(+91)区号的手机号,已在Login.js中根据登录手机号的区号,通过Redux分发setUS/setNonUS动作标记区域状态。尝试在constants.js中用useSelector获取Redux的isUS状态动态切换BaseUrl时,触发了「Invalid hook call」错误。此前单一BaseUrl声明时运行正常,需要修复该问题,同时保证其他组件仍能通过import {BaseUrl} from '../../utility/constants'的方式正常导入BaseUrl及相关EndPoint。

相关代码示例

Login.js

let BaseUrl;
if (userLoginModel.code === '+91') {
  dispatch(setNonUS());     
} else if (userLoginModel.code === '+1') {
  dispatch(setUS());     
}

constants.js(错误写法)

// constants.js
import {useSelector} from 'react-redux';

let BaseUrl;
const isUS = useSelector(state => state.settings.isUS);
if (isUS) {
  BaseUrl = 'https://us.herokuapp.com/api/v1';
} else {
  BaseUrl = 'https://india.herokuapp.com/api/v1';
}

export {BaseUrl};

const customersHub = BaseUrl + '/customers';
const salesHub = BaseUrl + '/sales';

export const EndPoint = {
  login: customersHub + '/addCustomer',
  getSales: salesHub + '/getSalesOfCustomer',
  getCustomer: customersHub + '/getCustomer',
}

错误原因

useSelector是React Hook,只能在React组件的顶层或自定义Hook的顶层调用,不能在普通JS工具模块(如constants.js)中直接使用,违反了Hook的使用规则,因此抛出Invalid hook call错误。

解决方案

方案一:用自定义Hook封装动态常量

这种方式既遵守Hook规则,又能让组件通过统一的方式获取最新的BaseUrl和EndPoint:

修改constants.js:

// constants.js
// 定义基础域名常量
const US_BASE_URL = 'https://us.herokuapp.com/api/v1';
const IN_BASE_URL = 'https://india.herokuapp.com/api/v1';

// 自定义Hook,用于组件中获取当前的BaseUrl和EndPoint
import { useSelector } from 'react-redux';
export const useAppConstants = () => {
  const isUS = useSelector(state => state.settings.isUS);
  const baseUrl = isUS ? US_BASE_URL : IN_BASE_URL;
  
  // 动态生成EndPoint
  const customersHub = baseUrl + '/customers';
  const salesHub = baseUrl + '/sales';
  
  return {
    BaseUrl: baseUrl,
    EndPoint: {
      login: customersHub + '/addCustomer',
      getSales: salesHub + '/getSalesOfCustomer',
      getCustomer: customersHub + '/getCustomer',
    },
  };
};

// 兼容非组件环境(如API工具类)的同步获取方法
import store from '../path/to/your/store'; // 导入你的Redux store实例
export const getBaseUrl = () => {
  const isUS = store.getState().settings.isUS;
  return isUS ? US_BASE_URL : IN_BASE_URL;
};

export const getEndPoints = () => {
  const baseUrl = getBaseUrl();
  const customersHub = baseUrl + '/customers';
  const salesHub = baseUrl + '/sales';
  
  return {
    login: customersHub + '/addCustomer',
    getSales: salesHub + '/getSalesOfCustomer',
    getCustomer: customersHub + '/getCustomer',
  };
};

在组件中使用:

// 业务组件示例
import { useAppConstants } from '../../utility/constants';

const SalesComponent = () => {
  const { BaseUrl, EndPoint } = useAppConstants();
  
  const fetchSalesData = async () => {
    try {
      const response = await fetch(EndPoint.getSales);
      const data = await response.json();
      // 处理数据
    } catch (err) {
      console.error(err);
    }
  };
  
  return (
    // 组件UI
  );
};

方案二:在Redux中直接维护BaseUrl状态

在登录时直接将BaseUrl存入Redux状态,后续从store中获取:

  1. 更新Redux reducer,添加baseUrl字段:
// settingsReducer.js
const initialState = {
  isUS: false,
  baseUrl: 'https://india.herokuapp.com/api/v1', // 默认印度域名
};

const settingsReducer = (state = initialState, action) => {
  switch(action.type) {
    case 'SET_US':
      return { ...state, isUS: true, baseUrl: 'https://us.herokuapp.com/api/v1' };
    case 'SET_NON_US':
      return { ...state, isUS: false, baseUrl: 'https://india.herokuapp.com/api/v1' };
    default:
      return state;
  }
};

export default settingsReducer;
  1. 修改Login.js,无需额外分发动作(reducer中已同步更新baseUrl):
// Login.js
if (userLoginModel.code === '+91') {
  dispatch(setNonUS());     
} else if (userLoginModel.code === '+1') {
  dispatch(setUS());     
}
  1. 更新constants.js,用自定义Hook或同步方法获取:
// constants.js
import { useSelector } from 'react-redux';
import store from '../path/to/your/store';

// 组件中使用的Hook
export const useAppConstants = () => {
  const baseUrl = useSelector(state => state.settings.baseUrl);
  
  const customersHub = baseUrl + '/customers';
  const salesHub = baseUrl + '/sales';
  
  return {
    BaseUrl: baseUrl,
    EndPoint: {
      login: customersHub + '/addCustomer',
      getSales: salesHub + '/getSalesOfCustomer',
      getCustomer: customersHub + '/getCustomer',
    },
  };
};

// 非组件环境使用的同步方法
export const getBaseUrl = () => store.getState().settings.baseUrl;

export const getEndPoints = () => {
  const baseUrl = getBaseUrl();
  const customersHub = baseUrl + '/customers';
  const salesHub = baseUrl + '/sales';
  
  return {
    login: customersHub + '/addCustomer',
    getSales: salesHub + '/getSalesOfCustomer',
    getCustomer: customersHub + '/getCustomer',
  };
};

注意事项

  • 严格遵守React Hook使用规则:只能在组件或自定义Hook的顶层调用Hook,不能在普通JS模块、循环、条件判断中使用。
  • 若需在非组件环境(如API请求工具类)中使用BaseUrl,直接从Redux store实例中同步获取状态,避免使用Hook。
  • 动态生成EndPoint时,确保每次获取都是基于最新的BaseUrl,避免缓存旧值导致请求错误。

内容的提问来源于stack exchange,提问作者Piyush Chatterjee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:12:53