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
相关产品推荐
相关产品推荐

