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

如何为React商家列表项添加查看详情按钮并调用API?

实现React商家卡片的“查看详情”功能

嘿,这事儿不难,我给你拆解成几个步骤,一步步来实现:

1. 给商家卡片添加Materialize风格的“查看”按钮

首先,在你的BusinessCard组件里,把“查看”按钮加进去,用Materialize的按钮样式就行。记得把商家的id作为参数传给点击事件处理函数:

// BusinessCard.jsx
const BusinessCard = ({ business, onViewDetails }) => {
  return (
    <div className="card small">
      <div className="card-content">
        <span className="card-title">{business.name}</span>
        <p>地址:{business.address}</p>
        <p>评分:{business.rating}</p>
      </div>
      <div className="card-action">
        {/* Materialize风格按钮,绑定点击事件并传入商家id */}
        <button 
          className="waves-effect waves-light btn"
          onClick={() => onViewDetails(business.id)}
        >
          查看详情
        </button>
      </div>
    </div>
  );
};

export default BusinessCard;

2. 在父组件中实现详情请求逻辑

接下来,在渲染商家列表的父组件里,我们需要管理详情数据、加载状态和错误状态,同时写一个发送API请求的函数:

// BusinessList.jsx
import { useState } from 'react';
import BusinessCard from './BusinessCard';

const BusinessList = ({ businesses }) => {
  // 状态管理:选中的商家详情、加载状态、错误信息
  const [selectedBusiness, setSelectedBusiness] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  // 发送请求获取商家详情的函数
  const handleViewDetails = async (businessId) => {
    setIsLoading(true);
    setError(null);
    setSelectedBusiness(null);

    try {
      // 使用AbortController防止组件卸载后请求仍在进行
      const controller = new AbortController();
      const signal = controller.signal;

      const response = await fetch(`/businesses/${businessId}`, { signal });
      if (!response.ok) {
        throw new Error('获取详情失败,请稍后重试');
      }
      const data = await response.json();
      setSelectedBusiness(data);
    } catch (err) {
      // 排除用户主动取消请求的情况
      if (err.name !== 'AbortError') {
        setError(err.message);
      }
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="row">
      {/* 渲染商家卡片列表 */}
      {businesses.map(business => (
        <div key={business.id} className="col s12 m6 l4">
          <BusinessCard 
            business={business} 
            onViewDetails={handleViewDetails}
          />
        </div>
      ))}

      {/* 展示加载状态 */}
      {isLoading && <div className="progress"><div className="indeterminate"></div></div>}

      {/* 展示错误信息 */}
      {error && <div className="red-text center-align">{error}</div>}

      {/* 展示商家详情(用Materialize模态框更友好) */}
      {selectedBusiness && (
        <div className="modal open">
          <div className="modal-content">
            <h4>{selectedBusiness.name}</h4>
            <p>完整地址:{selectedBusiness.fullAddress}</p>
            <p>联系方式:{selectedBusiness.phone}</p>
            <p>营业时间:{selectedBusiness.hours}</p>
            {/* 其他你需要展示的属性 */}
          </div>
          <div className="modal-footer">
            <button 
              className="modal-close waves-effect waves-green btn-flat"
              onClick={() => setSelectedBusiness(null)}
            >
              关闭
            </button>
          </div>
        </div>
      )}
    </div>
  );
};

export default BusinessList;

3. 额外优化点

  • Materialize模态框初始化:如果你用的是Materialize的模态框,记得在组件挂载时初始化它(可以用useEffect),或者使用Materialize的React封装库,这样模态框的显示/隐藏会更顺畅。
  • 避免重复请求:可以给按钮加个禁用状态,在isLoading为true时禁用按钮,防止用户多次点击。
  • axios替代fetch:如果你习惯用axios,请求逻辑可以改成这样:
import axios from 'axios';

// ...
const handleViewDetails = async (businessId) => {
  setIsLoading(true);
  setError(null);
  setSelectedBusiness(null);

  try {
    const response = await axios.get(`/businesses/${businessId}`);
    setSelectedBusiness(response.data);
  } catch (err) {
    setError(err.response?.data?.message || '获取详情失败');
  } finally {
    setIsLoading(false);
  }
};
// ...

这样一套下来,用户点击“查看”按钮就能获取对应商家的完整详情,并且有加载状态和错误提示,体验也不错~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:04:40