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

React多接口数据获取与权限条件渲染技术问询

问题

我正在构建MERN栈应用,需求为:管理员登录时以表格形式渲染全部商品,非管理员登录时以卡片形式渲染在售商品。目前我在Products.js页面尝试通过多fetch获取数据,代码如下:

//Products.js
import { Fragment, useEffect, useState, useContext } from "react";
import { Container, Table } from "react-bootstrap";
import ProductCard from "../components/ProductCard";

import UserContext from "../UserContext";

export default function Products() {
  const { user } = useContext(UserContext);
  const [userProducts, setUserProducts] = useState([]);
  const [adminProducts, setAdminProducts] = useState([]);

  // FETCH DATA
  useEffect(() => {
    fetchAdminProducts();
  }, []);

  useEffect(() => {
    fetchUserProducts();
  }, []);

  const fetchAdminProducts = () => {
    fetch("http://localhost:4000/products/all")
      .then((res) => res.json())
      .then((data) => {
        setAdminProducts(data);
      });
  };

  const fetchUserProducts = () => {
    fetch("http://localhost:4000/products/")
      .then((res) => res.json())
      .then((data) => {
        setUserProducts(data);
      });
  };

  return (
        <Fragment>
            <Container>
              {user.isAdmin === true ?
              (...) :
              (...)} 
            </Container>
        </Fragment>
    );
}

请问当前写法是否正确?如何将管理员商品数据映射到表格、用户商品数据映射到卡片?登录状态下多数据获取与条件渲染的最优方案是什么?


当前写法的问题分析

当前写法能实现基础功能,但存在明显冗余和潜在问题:

  • 无论用户角色,都会同时发起两个请求,浪费服务器资源和带宽——非管理员不需要全量商品数据,管理员也不需要在售商品子集。
  • 未处理请求失败场景(如网络错误、接口返回异常),会导致数据无法更新但无任何提示。
  • 初始渲染时user可能未加载完成(比如从localStorage读取或异步获取用户信息),此时user.isAdmin为undefined,会引发条件判断错误。

数据映射实现

管理员表格渲染

利用React Bootstrap的Table组件,遍历adminProducts生成表格行:

{user?.isAdmin && (
  <Table striped bordered hover>
    <thead>
      <tr>
        <th>ID</th>
        <th>商品名称</th>
        <th>价格</th>
        <th>状态</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      {adminProducts.map(product => (
        <tr key={product._id}>
          <td>{product._id}</td>
          <td>{product.name}</td>
          <td>{product.price}</td>
          <td>{product.isActive ? '在售' : '下架'}</td>
          <td>
            {/* 可添加编辑/删除等操作按钮 */}
          </td>
        </tr>
      ))}
    </tbody>
  </Table>
)}

用户卡片渲染

遍历userProducts,渲染自定义ProductCard组件:

{!user?.isAdmin && (
  <div className="d-flex flex-wrap gap-3">
    {userProducts.map(product => (
      <ProductCard 
        key={product._id}
        product={product}
      />
    ))}
  </div>
)}

最优方案优化

1. 按需发起请求

根据用户角色动态选择请求接口,避免冗余请求:

const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
  if (!user) return; // 等待用户信息加载完成

  const fetchUrl = user.isAdmin 
    ? "http://localhost:4000/products/all" 
    : "http://localhost:4000/products/";

  setLoading(true);
  fetch(fetchUrl)
    .then(res => {
      if (!res.ok) throw new Error('请求失败');
      return res.json();
    })
    .then(data => {
      setProducts(data);
      setError(null);
    })
    .catch(err => {
      setError(err.message);
      setProducts([]);
    })
    .finally(() => {
      setLoading(false);
    });
}, [user]); // 依赖user,角色变化时自动重新请求

2. 完善加载与错误状态处理

在渲染层添加状态提示,提升用户体验:

return (
  <Fragment>
    <Container>
      {loading && <p>加载中...</p>}
      {error && <p className="text-danger">{error}</p>}
      {!loading && !error && (
        user?.isAdmin ? (
          {/* 管理员表格 */}
          <Table striped bordered hover>
            <thead>
              <tr>
                <th>ID</th>
                <th>商品名称</th>
                <th>价格</th>
                <th>状态</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
              {products.map(product => (
                <tr key={product._id}>
                  <td>{product._id}</td>
                  <td>{product.name}</td>
                  <td>{product.price}</td>
                  <td>{product.isActive ? '在售' : '下架'}</td>
                  <td>
                    {/* 操作按钮 */}
                  </td>
                </tr>
              ))}
            </tbody>
          </Table>
        ) : (
          {/* 用户卡片 */}
          <div className="d-flex flex-wrap gap-3">
            {products.map(product => (
              <ProductCard 
                key={product._id}
                product={product}
              />
            ))}
          </div>
        )
      )}
    </Container>
  </Fragment>
);

3. 安全判断用户角色

使用可选链操作符?.避免user未加载时的报错:

{user?.isAdmin ? (...) : (...)}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 14:22:01