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

React Hooks实现动态触发:为每条服务端数据添加独立状态

解决React每条数据独立状态控制的问题

嘿,我来帮你搞定这个每条数据独立控制显示状态的需求!先看看你现有代码里的几个关键问题:

  • 你在渲染逻辑里直接调用setPanduan,这会触发无限重渲染(因为setState会导致组件重新渲染,渲染又调用setState)
  • 当前的panduan状态结构没法对应每条数据的独立状态,数组形式很难精准控制某一条的显示/隐藏

下面是针对你的需求的完整解决方案:

核心思路

我们需要给每条从服务端获取的数据绑定一个唯一标识(比如每条数据自带的id),用这个标识来跟踪该条数据的展开/收起状态。推荐用对象类型的状态来存储,键是数据的id,值是布尔值(true表示显示,false表示隐藏),这样能精准控制每一条的状态。

修改后的完整代码

function RekapAngkatan({ auth, getProposalRecapByYear, getReportRecapByYear, posts, StickyNav }) {
  const postingan = posts.posts;
  // 用对象存储每条数据的展开状态,键是post的id,值是布尔值
  const [expandedItems, setExpandedItems] = React.useState({});
  const [loading, setLoading] = React.useState(true); // 补全你之前缺失的loading状态定义

  React.useEffect(() => {
    const fetchData = async () => {
      if (auth.isAuthenticated) {
        try {
          // 并行请求两个接口,提升加载效率
          await Promise.all([
            getProposalRecapByYear(),
            getReportRecapByYear()
          ]);
        } catch (err) {
          console.error('数据请求失败:', err);
        } finally {
          setLoading(false); // 请求完成后结束加载状态
        }
      }
    };

    fetchData();
  }, [auth, getProposalRecapByYear, getReportRecapByYear]);

  // 切换指定id数据的展开/收起状态
  const toggleItem = (postId) => {
    setExpandedItems(prevState => ({
      ...prevState,
      [postId]: !prevState[postId] // 对指定id的状态取反
    }));
  };

  if (loading) {
    return <Loading />;
  }

  // 渲染每条数据
  return postingan.data.map((post) => {
    // 必须用post的唯一id作为key,不要用index,避免渲染异常
    return (
      <Section bg="transparent" margin="0 1.5em" padding="0 2em" key={post.id}>
        <div className="info-color">
          {post.value}
          <FakeButton 
            bg="#8C489F" 
            type="button" 
            onClick={() => toggleItem(post.id)}
          >
            {/* 根据当前状态切换按钮文字 */}
            {expandedItems[post.id] ? 'Caret Up' : 'Caret Down'}
          </FakeButton>
          {/* 根据对应id的状态控制属性组件的显示 */}
          {expandedItems[post.id] && (
            <Attribute>
              {/* 这里渲染你需要的proposal和laporan akhir属性 */}
              <div>Proposal: {post.proposal}</div>
              <div>Laporan Akhir: {post.laporanAkhir}</div>
              <div>Amount: {post.amount}</div>
            </Attribute>
          )}
        </div>
      </Section>
    );
  });
}

关键修改点说明

  1. 状态结构优化:把原来的数组状态panduan改成对象expandedItems,每条数据的id作为键,这样能精准定位到某一条的状态。
  2. 避免无限重渲染:移除了渲染逻辑里的setPanduan调用,所有状态更新都放在toggleItem函数里,只有点击按钮时才触发。
  3. 请求逻辑优化:用Promise.all并行请求两个接口,统一处理加载状态,避免重复请求。
  4. key的正确使用:用数据的唯一id作为map的key,而不是index,这是React性能优化和避免渲染错误的最佳实践。
  5. 状态切换逻辑:使用函数式更新setExpandedItems(prevState => ...),确保每次状态更新都是基于最新的状态值,避免闭包陷阱。

额外提示

  • 如果你的数据里没有id字段,可以用其他唯一标识(比如value或者组合字段),只要保证每条数据的标识唯一就行。
  • 如果需要默认展开某些条目,可以在初始化状态的时候设置,比如const [expandedItems, setExpandedItems] = React.useState({ 1: true, 3: true });(假设id为1和3的条目默认展开)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 16:22:37