Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在React after多个异步useState设置程序中运行一些代码_Javascript_Reactjs - Fatal编程技术网

Javascript 在React after多个异步useState设置程序中运行一些代码

Javascript 在React after多个异步useState设置程序中运行一些代码,javascript,reactjs,Javascript,Reactjs,我有一个功能性的React组件,在其中我使用useState来管理状态。通常,它只是一个包含两个字段的表单-code和env,用户可以手动填写并提交。但是,当组件加载时,我还想检查任何querystring参数,如果存在合适的参数,我想自动填充并提交表单。这样,用户就可以为特定的表单提交添加书签 我遇到的问题是,众所周知,useStatesetter是异步的,就像setState类内组件一样。由于这两个表单字段都由状态控制,设置这两个值将启动多个渲染,因此我应该将提交表单的代码放在哪里,以确保两

我有一个功能性的React组件,在其中我使用
useState
来管理状态。通常,它只是一个包含两个字段的表单-
code
env
,用户可以手动填写并提交。但是,当组件加载时,我还想检查任何querystring参数,如果存在合适的参数,我想自动填充并提交表单。这样,用户就可以为特定的表单提交添加书签

我遇到的问题是,众所周知,
useState
setter是异步的,就像
setState
类内组件一样。由于这两个表单字段都由状态控制,设置这两个值将启动多个渲染,因此我应该将提交表单的代码放在哪里,以确保两个状态更新都已完成

表格如下:

下面是我所拥有的代码的简化、净化版本:

import React, { useState, useEffect } from "react";

import axios from "axios";
import queryString from "query-string";
import Form from "react-bootstrap/Form";
import Button from "react-bootstrap/Button";
import ToggleButtonGroup from "react-bootstrap/ToggleButtonGroup";
import ToggleButton from "react-bootstrap/ToggleButton";
import Card from "react-bootstrap/Card";

/*
 * this component will show a spinner or the results from the API when complete
 */ 
const PortalDisplay = ({ data: portal, isLoading }) => {
  if (Object.keys(portal).length === 0 && !isLoading) {
    return null;
  } else if (isLoading) {
    return (
      <div>
        <p>loading&hellip;</p>
      </div>
    );
  } else if (!!portal.id && !isLoading) {
    return <div className="card-portal">data goes here</div>;
  }
};

/*
 * main component
 */     
const PortalConfiguration = () => {
  const [validated, setValidated] = useState(false);
  const [code, setCode] = useState("");
  const [env, setEnv] = useState("prod");
  const [portalInfo, setPortalInfo] = useState({});
  const [isLoading, setIsLoading] = useState(false);

  const params = queryString.parse(location.search);

  const onSubmitForm = (event) => {
    const form = event.currentTarget;
    setValidated(true);

    if (form.checkValidity() === false) {
      event.preventDefault();
      event.stopPropagation();
      return;
    }
    //re-initialize
    setIsLoading(true);
    setPortalInfo({});

    axios
      .get(`http://www.example.com/api`)
      .then((response) => {
        setIsLoading(false);
        setPortalInfo({ ...response.data, ...{ baseUrl: baseUrl[env] } });
      })
      .catch((error) => console.log(error));

    event.preventDefault();
    event.stopPropagation();
  };

  useEffect(() => {
    if (!!params && !!params.portal && !!params.env) {
      if (!/^[a-zA-Z]{3}$/.test(params.portal) || (params.env !== "prod" && params.env !== "demo")) {
        console.log(`Specified portal parameters {portal: ${params.portal}} and {env: ${params.env}} are incorrect`);
      } else {
        // this is where i want to set the portal and env states and submit the form
      }
    }
  }, [params.portal]);

  return (
    <>
      <h1>Your Portal Configuration</h1>

      <Card>
        <Card.Body>
          <Form noValidate validated={validated} inline className="form-portal" onSubmit={onSubmitForm}>
            <Form.Group className="form-group-code">
              <label className="sr-only" htmlFor="code">
                Portal Code
              </label>
              <Form.Control
                type="text"
                id="code"
                value={code}
                required
                placeholder="Enter Portal Code (e.g. 'FWU')"
                maxLength="3"
                onChange={(e) => setCode(e.target.value)}
              />
              <Form.Control.Feedback type="invalid">Portal Code must be three letters (a-z)</Form.Control.Feedback>
            </Form.Group>
            <Form.Group>
              <ToggleButtonGroup type="radio" name="env" value={env} onChange={(val) => setEnv(val)}>
                <ToggleButton type="radio" name="env" value="prod" variant="primary" className="btn-inline">
                  Production
                </ToggleButton>
                <ToggleButton type="radio" name="env" value="demo" variant="primary" className="btn-inline">
                  Demo
                </ToggleButton>
              </ToggleButtonGroup>
            </Form.Group>

            <Button variant="secondary" block="true" className="btn-inline" type="submit">
              Submit
            </Button>
          </Form>
        </Card.Body>
      </Card>
      <PortalDisplay data={portalInfo} isLoading={isLoading} env={env} />
    </>
  );
};
export default PortalConfiguration;
import React,{useState,useffect}来自“React”;
从“axios”导入axios;
从“查询字符串”导入查询字符串;
从“react引导/表单”导入表单;
从“反应引导/按钮”导入按钮;
从“react bootstrap/ToggleButtongGroup”导入ToggleButtongGroup;
从“react bootstrap/ToggleButton”导入ToggleButton;
从“反应引导/卡”导入卡;
/*
*完成后,此组件将显示微调器或API的结果
*/ 
const PortalDisplay=({data:portal,isLoading})=>{
if(Object.keys(portal.length==0&&!isLoading){
返回null;
}else if(正在加载){
返回(
加载和hellip

); }否则如果(!!portal.id&&!isLoading){ 返回数据在这里; } }; /* *主要成分 */ 常量端口配置=()=>{ const[validated,setValidated]=useState(false); const[code,setCode]=useState(“”); const[env,setEnv]=useState(“prod”); const[portalInfo,setPortalInfo]=useState({}); const[isLoading,setIsLoading]=useState(false); const params=queryString.parse(location.search); const onSubmitForm=(事件)=>{ const form=event.currentTarget; setValidated(true); if(form.checkValidity()==false){ event.preventDefault(); event.stopPropagation(); 返回; } //重新初始化 设置加载(真); setPortalInfo({}); axios .得到(`http://www.example.com/api`) 。然后((响应)=>{ 设置加载(假); setPortalInfo({…response.data,{baseUrl:baseUrl[env]}}); }) .catch((错误)=>console.log(错误)); event.preventDefault(); event.stopPropagation(); }; useffect(()=>{ if(!!params&&!!params.portal&&!!params.env){ if(!/^[a-zA-Z]{3}$/.test(params.portal)| |(params.env!=“prod”&¶ms.env!=“demo”)){ log(`指定的门户参数{portal:${params.portal}}和{env:${params.env}}不正确'); }否则{ //这就是我想要设置门户和环境状态并提交表单的地方 } } },[params.portal]); 返回( 您的门户配置 门户代码 设置代码(e.target.value)} /> 门户代码必须为三个字母(a-z) setEnv(val)}> 生产 演示 提交 ); }; 导出默认端口配置;
注释掉的一行说“这是我想设置门户和环境状态并提交表单的地方”,我知道我已经传递了querystring参数,需要设置这两种状态,然后提交表单


FWIW,对于如何处理
useState
的异步性,我已经考虑了通常的答案,即在
useffect
中处理它,范围是您感兴趣的特定状态变量。这有两个问题:1)我有两个状态变量需要更新,因此我认为不能保证它们会按照我调用setters的顺序更新,从而创建一个可能的竞争条件;2)我不想每次
code
env
更新时都调用此代码,当用户手动与表单交互时会发生这种情况。我只希望在组件在加载时检测到查询字符串时自动提交它。

是否将这两个字段组合成类似于
useState({code:'',env:'prod
})`的选项?钩子版本,
useState
一次只能处理一个状态变量。我想我可以把整个东西重构成一个类组件,使
setState
可用,你可以一次设置多个状态。但您仍然会遇到问题,何时提交表单以确保状态已成功设置?是否可以将这两个字段组合成类似于
useState({code:'',env:'prod
})`的选项?钩子版本,
useState
一次只能处理一个状态变量。我想我可以把整个东西重构成一个类组件,使
setState
可用,你可以一次设置多个状态。但您仍然遇到问题,何时提交表单以确保状态已成功设置?