基于下拉选择动态获取URL并渲染对应组件的技术求助
问题描述
我正在开发一款仪表盘系统,主菜单包含多个选项,用户选择菜单选项后会进入环境选择下拉菜单。根据所选环境,系统会以表格形式渲染对应数据。目前已通过硬编码Prod1环境的URL实现了该环境下的内容渲染,但希望为其他环境也实现相同功能,同时避免逻辑重复,寻求帮助实现基于下拉选择动态获取对应环境URL的方案。
现有代码
Menu.js
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
相关产品推荐
相关产品推荐

