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

基于下拉选择动态获取URL并渲染对应组件的技术求助

问题描述

我正在开发一款仪表盘系统,主菜单包含多个选项,用户选择菜单选项后会进入环境选择下拉菜单。根据所选环境,系统会以表格形式渲染对应数据。目前已通过硬编码Prod1环境的URL实现了该环境下的内容渲染,但希望为其他环境也实现相同功能,同时避免逻辑重复,寻求帮助实现基于下拉选择动态获取对应环境URL的方案。


现有代码

const Menu = () => {
  return (
    <div className='menu'>
        <div className='item'>
           <Stack alignItems='center' direction='row'> 
              <Typography variant='body1'>Details</Typography>
           </Stack>
           <Link to="/product">
              <Typography variant='body1'>Product</Typography>
           </Link>
           <Link to="/customer">
              <Typography variant='body1'>Customer</Typography>
           </Link>
        </div>
    </div>
  )
}

App.js

function App () {
  const router = createBrowserRouter ([
    {
     path: "/product",
     element: <SelectEnvironment />
    },
    {
     path: "/customer",
     element: <SelectEnvironment />
    },
    { 
     path: "/account",
     element: <SelectEnvironment />
    }
  ]);
 return (<RouterProvider router={router}/>);
}
export default App;

SelectEnvironment.js

function SelectEnvironment() {
   const[environment, setEnvironment] = useState("selectEnvironment");
   const[prod1DetailsVisible, setProd1DetailsVisible] = useState(false);
   const[prod2DetailsVisible, setProd2DetailsVisible] = useState(false);

   const handleOnChange = (event) => {
    setEnvironment(event.target.value);
   }

   useEffect(() => {
     setProd1DetailsVisible(environment === 'prod1');
     setProd2DetailsVisible(environment === 'prod2');
   }, [environment]);

   return (
      <div className='environment selection'>
        <div>
          <Typography variant='body1'> Select </Typography>
        </div>

        <div className='environment list'>
          <select className='form select' value={environment} onChange={handleOnChange}>
             <option value='selectEnvironment'>select</option>
             <option value='prod1'>PROD1</option>
             <option value='prod2'>PROD2</option>
          </select>
        </div>
        {prod1DetailsVisible && <ProductTable environment={environment}/>}
        {prod2DetailsVisible && <ProductTable environment={environment}/>}
     </div>
    )
}
export default SelectEnvironment;

ProductTable.js

function ProductTable({ environment }) {
    const dispatch = useDispatch();
    const list = useSelector((state) => state.product.products);
    
    useEffect(() => {
       dispatch(getProduct(environment));
    }, [dispatch, environment]);

    return (
       <>
         <Grid container>
           <Grid item xs={12}>
             <TableContainer component={Paper}>
               <Table sx={{minWidth:650}} aria-label='simple table'>
                 <TableHead>
                    <TableRow>
                       <TableCell>
                         <b> Product Id </b>
                       </TableCell>
                       <TableCell>
                         <b> Product Name </b>
                       </TableCell>
                    </TableRow>
                 </TableHead>
                 <TableBody>
                    {
                      list.map((row) => (
                        <TableRow key={row?.id}>
                           <TableCell component='th' scope='row'>{row?.id}</TableCell>
                           <TableCell >{row?.name}</TableCell>
                        </TableRow>
                    ))}
                 </TableBody>
               </Table>
             </TableContainer>
           </Grid>
         </Grid>
       </> 
    );
}
export default ProductTable;

CustomerTable.js

function CustomerTable({ environment }) {
    const dispatch = useDispatch();
    const list = useSelector((state) => state.customer.customers);
    
    useEffect(() => {
       dispatch(getCustomer(environment));
    }, [dispatch, environment]);

    return (
       <>
         <Grid container>
           <Grid item xs={12}>
             <TableContainer component={Paper}>
               <Table sx={{minWidth:650}} aria-label='simple table'>
                 <TableHead>
                    <TableRow>
                       <TableCell>
                         <b> Customer Id </b>
                       </TableCell>
                       <TableCell>
                         <b> Customer Name </b>
                       </TableCell>
                    </TableRow>
                 </TableHead>
                 <TableBody>
                    {
                      list.map((row) => (
                        <TableRow key={row?.id}>
                           <TableCell component='th' scope='row'>{row?.id}</TableCell>
                           <TableCell >{row?.name}</TableCell>
                        </TableRow>
                    ))}
                 </TableBody>
               </Table>
             </TableContainer>
           </Grid>
         </Grid>
       </> 
    );
}
export default CustomerTable;

store -> action -> index.js

// 集中管理各环境API地址
const ENV_URLS = {
  prod1: {
    product: "PROD1_PRODUCT_API_URL",
    customer: "PROD1_CUSTOMER_API_URL"
  },
  prod2: {
    product: "PROD2_PRODUCT_API_URL",
    customer: "PROD2_CUSTOMER_API_URL"
  }
};

export const getProduct = (environment) => (dispatch) => {
  const targetUrl = ENV_URLS[environment]?.product;
  if (!targetUrl) return;

  fetch(targetUrl)
    .then(response => response.json())
    .then(data => {
      dispatch({ type: GET_PRODUCT, payload: data }); 
    }) 
    .catch(error => console.log(error));
};

export const getCustomer = (environment) => (dispatch) => {
  const targetUrl = ENV_URLS[environment]?.customer;
  if (!targetUrl) return;

  fetch(targetUrl)
    .then(response => response.json())
    .then(data => {
      dispatch({ type: GET_CUSTOMER, payload: data }); 
    }) 
    .catch(error => console.log(error));
};

store -> reducer -> type.js

const initialState = {
  products: []
};

const initialStateCust = {
  customers: []
};

export const product = (state = initialState, action) => {
  switch(action.type) {
    case GET_PRODUCT:
      return { ...state, products: action.payload };
    default:
      return state;
  }
};

export const customer = (state = initialStateCust, action) => {
  switch(action.type) {
    case GET_CUSTOMER:
      return { ...state, customers: action.payload };
    default:
      return state;
  }
};

实现方案说明

1. 集中管理环境URL

通过ENV_URLS对象统一存储不同环境下的API地址,避免硬编码,后续新增环境或修改地址只需维护这个对象即可。

2. 动态传递环境参数

  • 在SelectEnvironment组件中,将选中的环境参数传递给Table组件
  • Table组件接收环境参数后,在请求数据时传递给action函数

3. 动态匹配API地址

action函数根据传入的环境参数,从ENV_URLS中获取对应API地址,发起请求并更新redux状态。

4. 代码优化与错误修复

  • 修正原代码中的拼写错误(如useSate→useState、mnWidth→minWidth)
  • 给reducer添加default分支,避免状态丢失
  • 简化环境显示状态的判断逻辑
  • 增加URL存在性校验,防止无效请求

5. 进一步优化方向

可以让SelectEnvironment组件根据当前路由自动匹配要渲染的Table组件,减少重复代码:

// SelectEnvironment.js中新增
import { useLocation } from 'react-router-dom';
import CustomerTable from './CustomerTable';

function SelectEnvironment() {
  const location = useLocation();
  
  const renderCurrentTable = () => {
    switch(location.pathname) {
      case '/product': return <ProductTable environment={environment}/>;
      case '/customer': return <CustomerTable environment={environment}/>;
      case '/account': return <AccountTable environment={environment}/>;
      default: return null;
    }
  };

  return (
    <div className='environment selection'>
      {/* 下拉选择区域 */}
      {(environment === 'prod1' || environment === 'prod2') && renderCurrentTable()}
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 05:34:50