多个状态更新完成后才调用函数

bis*_*ack 6 javascript reactjs

逻辑:

我有一个转换单位的对话框。它有两个阶段供用户选择:要转换的单位和要转换的单位。dialogStage为了可维护性,我将此阶段保留为一个状态,因为将来我可能需要参考对话框所处的阶段以获取更多功能。现在它被用来根据点击的单位确定要采取的行动。

我还有一个状态,dialogUnits,它会导致组件在更新时重新呈现。它是一个 JSX 元素数组,它通过foundUnitsArray或更新convertToUnitsArray,具体取决于对话框所处的阶段。当前,状态dialogStagedialogUnits都在问题发生的同时更新。

在此处输入图片说明

问题:

选择convertTo单位时,displayConversionTo()仍然被调用,好像dialogStage仍然设置为“initial”而不是“concertTo”。一些调试导致混乱,为什么if (dialogStage == 'initial')true当我的状态设置为“的ConvertTo”

我相信我的问题是dialogStage状态在handleUnitClick()被调用时没有及时更新,因为它是异步的。所以我设置了一个新的useEffect,只在dialogStage更新时调用。

现在的问题是对话框在初始选择后没有显示“convertTo”单位。我相信现在是因为dialogUnits没有及时更新?我已经将我原来的问题从一个状态没有准备好到另一个状态没有准备好。

在继续调用这里的函数之前,我如何等到两个状态都更新(例如handleUnitClick()?)。

还是我误会了问题所在?

我刚开始反应,到目前为止,我只熟悉状态更新在准备好时自动重新渲染组件的做法,除非被覆盖。更新dialogUnits是在对话框中显示新单位,直到我尝试仅在dialogStage准备好时才更新它。现在感觉就像是一种非此即彼的情况(在等待状态更新方面)而且我很可能忽略了一些更明显的东西,因为它似乎不适合在这么多情况下监听状态更新ReactJs 是围绕已经通过重新渲染等提供的内容构建的。

组件代码:

function DialogConvert(props) {

    const units = props.pageUnits;

    const [dialogUnits, setDialogUnits] = useState([]);
    const [dialogStage, setDialogStage] = useState('initial');

    let foundUnitsArray = [];
    let convertToUnitsArray = [];

    units.unitsFound.forEach(element => {
        foundUnitsArray.push(<DialogGroupChoice homogName={element} pcbOnClick={handleUnitClick} />);
    });

    useEffect(() => {
        setDialogUnits(foundUnitsArray);
    }, []);


    useEffect(() => {
        if (dialogStage == "convertTo") {
            setDialogUnits(convertToUnitsArray);
        }
    }, [dialogStage]);
    
    
    function handleClickClose(event) {
        setDialogStage('initial');
        props.callbackFunction("none");
    }


    function handleUnitClick(homogName) {
        if (dialogStage == "initial") {
            // getConversionChoices is an external function that returns an array. This returns fine and as expected
            const choices = getConversionChoices(homogName);
            displayConversionTo(choices);
        } else if (dialogStage == "convertTo") {
            // Can't get this far
            // Will call a function not displayed here once it works
        }
    }


    function displayConversionTo(choices) {
        let canConvertTo = choices[0]["canconvertto"];
        if (canConvertTo.length > 0) {
            canConvertTo.forEach(element => {
                convertToUnitsArray.push(<DialogGroupChoice homogName={element} pcbOnClick={handleUnitClick} />);
            });
            setDialogStage('convertTo');
        }
    }
    

    return (
        <React.Fragment>
            <div className="dialog dialog__convertunits" style={divStyle}>
                <h2 className="dialogheader">Convert Which unit?</h2>
                <div className='js-dialogspace-convertunits'>
                <ul className="list list__convertunits">
                    {dialogUnits}
                </ul>
                </div>
                <button className='button button__under js-close-dialog' onClick={handleClickClose}>Close</button>
            </div>
        </React.Fragment>
    )
}
Run Code Online (Sandbox Code Playgroud)

小智 4

因此,您的实现存在一些问题:

  1. 使用非状态变量来更新 useEffect 中的状态:

说明:displayConversionTo当您运行循环将元素推入convertToUnitsArray,然后将状态设置dialogStageconvertTo时,您应该面临更新值未渲染的问题,因为状态的更改会触发重新渲染并且 ConvertToUnitsArray 被重置由于以下行而变为空数组:

let convertToUnitsArray = [];
Run Code Online (Sandbox Code Playgroud)

因此,当您useEffect运行应该更新 dialogUnitstoconvertToUnitsArray时,它实际上应该将DialogueUnits 设置为空数组,因此在任何情况下,单击初始单位列表时更新的单位都不应该可见。

useEffect(() => {
  if (dialogStage == "convertTo") {
    // as your convertToUnitsArray is an empty array
    // your dialogue units should be set to an empty array.
    setDialogUnits(convertToUnitsArray)
  }
}, [dalogStage]);
Run Code Online (Sandbox Code Playgroud)
  1. 您试图在不建议的状态下存储一组反应组件: http://web.archive.org/web/20150419023006/http ://facebook.github.io/react/docs/interactivity-and- dynamic-uis.html#what-c​​omponents-should-have-state

另请参阅/sf/answers/3778371131/

解决方案:您可以做的就是尝试将数据保存在某种状态中,然后使用该状态渲染组件,我创建了一个代码沙箱示例,它应该如何适合您的应用程序。为了使这个示例正常工作,我还做了一些更改。