繁体   English   中英

React useState 被覆盖,即使有传播

[英]React useState overwritten even with spread

所以我有一个组件,我必须在其中进行 API 调用以获取一些具有我用于另一个异步 API 调用的 ID 的数据。 我的问题是我无法让异步 API 调用正常工作,通过传播 (...) 更新 state 以便可以在渲染中进行检查以显示与特定内容相关的特定阶段。

仅供参考:项目是一个无头 Drupal/React。

import WidgetButtonMenu from '../WidgetButtonMenu.jsx';
import { WidgetButtonType } from '../../Types/WidgetButtons.tsx';
import { getAllInitaitives, getInitiativeTaxonomyTerm } from '../../API/Initiatives.jsx';
import { useEffect } from 'react';
import { useState } from 'react';

import { stripHTML } from '../../Utilities/CommonCalls.jsx';

import '../../../CSS/Widgets/WidgetInitiativeOverview.css';

import iconAdd from '../../../Icons/Interaction/icon-add.svg';

function WidgetInitiativeOverview(props) {
    const [initiatives, setInitiatives] = useState([]);
    const [initiativesStages, setInitiativesStage] = useState([]);

    // Get all initiatives and data
    useEffect(() => {
        const stages = [];
        const asyncFn = async (initData) => {
            await Promise.all(initData.map((initiative, index) => {
                getInitiativeTaxonomyTerm(initiative.field_initiative_stage[0].target_id).then((data) => {
                    stages.push({
                        initiativeID: initiative.nid[0].value,
                        stageName: data.name[0].value
                    });
                });
            }));

            return stages;
        }

        // Call data
        getAllInitaitives().then((data) => {
            setInitiatives(data);
            asyncFn(data).then((returnStages) => {
                setInitiativesStage(returnStages);
            })
        });
    }, []);

    useEffect(() => {
        console.log('State of stages: ', initiativesStages);
    }, [initiativesStages]);

    return (
        <>
            <div className='widget-initiative-overview-container'>
                <WidgetButtonMenu type={ WidgetButtonType.DotsMenu } />
                { initiatives.map((initiative, index) => {
                    return (
                        <div className='initiative-container' key={ index }>
                            <div className='top-bar'>
                                <div className='initiative-stage'>
                                    { initiativesStages.map((stage, stageIndex) => {
                                        if (stage.initiativeID === initiative.nid[0].value) {
                                            return stage.stageName;
                                        }
                                    }) }
                                </div>
                                <button className='btn-add-contributors'><img src={ iconAdd } alt='Add icon.' /></button>
                            </div>
                            <div className='initiative-title'>{ initiative.title[0].value } - NID ({ initiative.nid[0].value })</div>
                            <div className='initiative-description'>{ stripHTML(initiative.field_initiative_description[0].processed) }</div>
                        </div>
                    );
                }) }
            </div>
        </>
    );
}

export default WidgetInitiativeOverview;

这是视频可视化的链接: https://vimeo.com/743753924 在视频中,您可以看到在页面刷新时,state 中没有数据,但如果我修改代码(例如放入空格)并保存它,数据会填充半秒并在组件中正确更新。

我尝试使用 spread 来确保 state 没有发生突变,但我仍在学习 React 的细节。

state 倡议工作正常,但话又说回来,这只是 1 个 API 调用然后设置数据。 InitiativeStages state 可以使用 X 数量的 API 调用,具体取决于在第一个 API 调用期间返回的倡议数量。

我不认为 API 调用对于这个问题是必要的,但如果需要,我可以参考它们。 同样,我认为这只是更新 state 的问题。

您传递给initData.map()的 function 不会返回任何内容,因此您的await Promise.all()正在等待一系列Promise.resolve(undefined) .你有机会调用stages.push({... });

这就是为什么你setInitiativesStage([])一个空数组。

你用const stages = [];做什么并且stages.push()内部的 stage.push( .then()是一种反模式,因为它会产生像您这样的损坏代码。

我就是这样写效果的:

useEffect(() => {
  // makes the request for a single initiative and transforms the result.
  const getInitiative = initiative => getInitiativeTaxonomyTerm(
      initiative.field_initiative_stage[0].target_id
    ).then(data => ({
      initiativeID: initiative.nid[0].value,
      stageName: data.name[0].value
    }))

  // Call data
  getAllInitaitives()
    .then((initiatives) => {
      setInitiatives(initiatives);

      Promise.all(initiatives.map(getInitiative))
        .then(setInitiativesStage);
    });
}, []);

这段代码仍然有一个缺陷(imo。)它首先更新setInitiatives ,然后开始让 API 自己调用 initiaives ,然后再更新setInitiativesStage 因此,这两种状态在一段时间内不同步。 您可能想延迟setInitiatives(initiatives); 直到其他 API 请求完成。

getAllInitaitives()
  .then(async (initiatives) => {
    const initiativesStages = await Promise.all(initiatives.map(getInitiative));
    
    setInitiatives(initiatives);
    setInitiativesStage(initiativesStages)
  });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM