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

ReactJS中点击LOAD按钮两次才显示异步MySQL请求数据的问题修复咨询

解决React中点击两次LOAD按钮才渲染异步数据的问题

嘿,这个问题我之前也碰到过,核心原因是React的状态更新是异步操作——你在调用setPessoas/setSubsistemas之后立刻执行imprimeBlocos(),此时状态还没完成更新,所以imprimeBlocos读取到的还是旧的subsistemas和pessoas值,自然渲染不出内容。第二次点击时,之前的状态已经更新完毕,所以才能正常显示。

下面给你两种解决方案,推荐第二种更符合React的设计思路:

方案一:利用setState的回调函数

React的setState(包括你用的setPessoas、setSubsistemas,如果是外部状态管理工具的setter通常也支持类似回调)允许传入第二个参数,这个回调会在状态完全更新完成后执行。我们可以把依赖新状态的逻辑放到这个回调里:

修改selecionaSubsistemas函数

async function selecionaSubsistemas(){ 
  return Axios.post("http://localhost:3001/api/selecionaSubsistemas", { })
    .then((response)=>{ 
      const newSubsistemas = response.data;
      // 等待组件内部状态更新后,再同步外部状态并调用下一个请求
      setSubsistemas(newSubsistemas, () => {
        dados.setSubsistemas(newSubsistemas);
        selecionaPessoas(); 
      });
    }); 
} 

修改selecionaPessoas函数

async function selecionaPessoas(){ 
  return Axios.post("http://localhost:3001/api/selecionaPessoas", { })
    .then((response)=>{ 
      const newPessoas = response.data;
      // 等待状态更新完成后,再执行渲染逻辑
      setPessoas(newPessoas, () => {
        dados.setPessoas(newPessoas);
        imprimeBlocos(); 
      });
    }); 
} 

这样就能确保每次状态更新完成后,才去调用依赖新状态的函数,点击一次LOAD按钮就能渲染内容了。

方案二:让组件自动根据状态渲染(推荐)

其实React的核心思想就是状态驱动视图,我们不需要手动调用setBlocos来更新视图,而是让blocos作为状态的计算值,当subsistemas或pessoas变化时自动更新。可以用useMemo来优化计算性能:

替换手动设置blocos的逻辑

首先删掉原来的imprimeBlocos和setBlocos,然后用useMemo生成blocos:

import { useMemo } from 'react';

// 在组件内部定义
const blocos = useMemo(() => {
  // 如果数据还没加载完成,返回加载提示或者null
  if (!dados.state.subsistemas || !dados.state.pessoas) {
    return <p>加载中...</p>;
  }

  const aux = []; 
  const subsistemas = dados.state.subsistemas; 
  
  for (let i = 0; i < subsistemas.length; i++) { 
    let children = []; 
    const subsistemasItem = subsistemas[i]; 
    const pessoas = dados.state.pessoas; 
    
    for (let j = 0; j < pessoas.length; j++) { 
      const pessoasItem = pessoas[j]; 
      if (pessoasItem.referenciaidsubsistema === subsistemasItem.idsubsistema) { 
        children.push(( 
          <div key={pessoasItem.idpessoa}> {/* 必须加唯一key,避免React警告 */}
            <p> {pessoasItem.nomecompleto} </p> 
            {/* 每个评分项的name要唯一,否则所有radio会互相干扰 */}
            <form> 
              <p>Comunicação</p> 
              <input 
                type="radio" 
                name={`comunicacao-${pessoasItem.idpessoa}`} 
                value="op1" 
                onClick={() => atualizaStateAvaliacao(pessoasItem.idpessoa,1,1)}
              /> Péssimo 
            </form> 
            <form> 
              <p>Companheirismo</p> 
              <input 
                type="radio" 
                name={`companheirismo-${pessoasItem.idpessoa}`} 
                value="op1" 
                onClick={() => atualizaStateAvaliacao(pessoasItem.idpessoa,2,1)}
              /> Péssimo 
            </form> 
            <form> 
              <p>Pontualidade</p> 
              <input 
                type="radio" 
                name={`pontualidade-${pessoasItem.idpessoa}`} 
                value="op1" 
                onClick={() => atualizaStateAvaliacao(pessoasItem.idpessoa,3,1)}
              /> Péssimo 
            </form> 
            <form> 
              <p>Proatividade</p> 
              <input 
                type="radio" 
                name={`proatividade-${pessoasItem.idpessoa}`} 
                value="op1" 
                onClick={() => atualizaStateAvaliacao(pessoasItem.idpessoa,4,1)}
              /> Péssimo 
            </form> 
            <form> 
              <p>Qualidade do trabalho</p> 
              <input 
                type="radio" 
                name={`qualidade-${pessoasItem.idpessoa}`} 
                value="op1" 
                onClick={() => atualizaStateAvaliacao(pessoasItem.idpessoa,5,1)}
              /> Péssimo 
            </form> 
          </div> 
        )); 
      } 
    } 
    aux.push(( 
      <React.Fragment key={subsistemasItem.idsubsistema}> 
        <p>{subsistemasItem.nome}</p> 
        {children} 
      </React.Fragment> 
    )); 
  } 
  aux.push(( 
    <React.Fragment key="qualquer"> 
      <div> 
        <br></br> 
        <button onClick={() => enviaAvaliacoes()}>ENVIAR</button> 
      </div> 
    </React.Fragment> 
  )); 
  return aux;
}, [dados.state.subsistemas, dados.state.pessoas]); // 依赖项:当这些状态变化时重新计算blocos

简化selecionaSubsistemas和selecionaPessoas

现在只需要更新状态,不需要手动调用渲染函数了:

async function selecionaPessoas(){ 
  return Axios.post("http://localhost:3001/api/selecionaPessoas", { })
    .then((response)=>{ 
      const newPessoas = response.data;
      setPessoas(newPessoas); 
      dados.setPessoas(newPessoas);
    }); 
} 

async function selecionaSubsistemas(){ 
  return Axios.post("http://localhost:3001/api/selecionaSubsistemas", { })
    .then((response)=>{ 
      const newSubsistemas = response.data;
      setSubsistemas(newSubsistemas); 
      dados.setSubsistemas(newSubsistemas);
      selecionaPessoas(); 
    }); 
} 

这样当subsistemas和pessoas加载完成后,blocos会自动重新计算,页面也会自动渲染,完全不需要手动触发,更符合React的设计理念。

额外的小优化

  • 给循环生成的元素添加唯一的key属性,避免React控制台警告。
  • 给每个radio的name属性设置唯一值(比如结合用户ID和评分项),否则同一页面的所有radio会被视为同一组,选择一个会取消其他的。
  • 添加加载状态提示,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 12:02:42