【问题标题】:How to conditionally render error in react js?如何在反应 js 中有条件地呈现错误?
【发布时间】:2021-03-18 10:54:53
【问题描述】:

我在 reactjs 中有一个带有材质 UI 组件的注册表单组件。我有一个对象数组,其中包含 TextField 组件的 props 值。如果字段值为空,我想有条件地显示“不能为空”帮助文本。例如,如果没有输入电子邮件,但输入了姓名,我应该显示唯一不能为空错误文本的电子邮件。

我面临的错误:我能够显示错误,但即使一个输入为空,所有字段都会显示错误。

预期:如果有任何错误,应该只显示对应的 TextField 的帮助文本

我试过了——CodeSandBox 链接https://codesandbox.io/s/infallible-joliot-6vkrq?file=/src/App.jsfile=/src/App.js

我可以通过什么方式改进这一点?任何帮助表示赞赏。谢谢:)

【问题讨论】:

  • 替代解决方案:Demo

标签: javascript reactjs


【解决方案1】:

这是因为您使用的是boolean。你应该使用一个对象:

import { Grid, TextField } from "@material-ui/core";
import { useState } from "react";
import "./styles.css";

export default function App() {
  const [inputErrors, setInputErrors] = useState({}); // PLURALIZED AND INITIALIZED WITH AN EMPTY OBJECT
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");

  const handleChange = (event, index, setValue, setError) => {
    let value = event.target.value;
    if (!value) {
      setError(state => ({
        ...state,
        [event.target.name]: true
      }));
    } else {
      setError(state => ({
        ...state,
        [event.target.name]: false
      }));
      setValue(value);
    }
  };

  const arrObj = [
    {
      name: "Name",
      input: "Please enter your name",
      onChange: (event, index) =>
        handleChange(event, index, setName, setInputErrors),
      helperText: inputErrors.name && "*Name is Required"
    },
    {
      name: "Email",
      input: "enter your email address",
      onChange: (event, index) =>
        handleChange(event, index, setEmail, setInputErrors),
      helperText: inputErrors.email && "*Email is Required"
    }
  ];

  return (
    <div className="App">
      {arrObj.map((item, index) => {
        let { onChange, input, helperText } = item;
        return (
          <Grid key={index} item xs={12} style={{ textAlign: "center" }}>
            <TextField
              name={item.name.toLowerCase()}
              placeholder={input}
              required
              onChange={(event) => onChange(event, index)}
              helperText={helperText}
            />
          </Grid>
        );
      })}
    </div>
  );
}


这里我们在输入字段上分配一个“名称”属性,并在代码中使用它作为错误的键。

【讨论】:

    【解决方案2】:

    您正在使用单个布尔状态 inputError 来确定 nameemail 字段的错误,这就是您看到错误的原因。无法区分错误发生在哪个字段。

    您可以有一个专用的inputError 对象作为您输入字段的Hashmap/Dictionary,而true/false 指示特定字段是否有错误。

    完整代码供参考:-

    import { Grid, TextField } from "@material-ui/core";
    import { useState } from "react";
    import "./styles.css";
    
    export default function App() {
      const [inputError, setInputError] = useState({ name: false, email: false });
      const [name, setName] = useState("");
      const [email, setEmail] = useState("");
    
      const handleChange = (event, index, setValue, setError) => {
        let { value, name } = event.target;
        name = name.toLowerCase();
        if (!value) setError({ ...inputError, [name]: true });
        else {
          setError({ ...inputError, [name]: false });
          setValue(value);
        }
      };
      const arrObj = [
        {
          name: "Name",
          input: "Please enter your name",
          onChange: (event, index) =>
            handleChange(event, index, setName, setInputError),
          helperText: inputError.name && "*Name is Required"
        },
        {
          name: "Email",
          input: "enter your email address",
          onChange: (event, index) =>
            handleChange(event, index, setEmail, setInputError),
          helperText: inputError.email && "*Email is Required"
        }
      ];
    
      return (
        <div className="App">
          {arrObj.map((item, index) => {
            let { onChange, input, helperText, name } = item;
            return (
              <Grid key={index} item xs={12} style={{ textAlign: "center" }}>
                <TextField
                  name={name}
                  placeholder={input}
                  required
                  onChange={(event) => onChange(event, index)}
                  helperText={helperText}
                />
              </Grid>
            );
          })}
        </div>
      );
    }
    
    

    Codesandbox Link

    【讨论】:

      【解决方案3】:

      您可以通过将TextField 包装在一个可以管理其自身状态的组件中来分解该通用逻辑。它将大大简化您的代码。

      import { Grid, TextField } from "@material-ui/core";
      import { useState } from "react";
      import "./styles.css";
      
      const RequiredTextField = ({item:{ input, helperText }, value}) => {
        const [inputValue, setValue] = useState(value);
        const [inputError, setInputError] = useState(true);
      
        const onChange = ({target:{value}}) => {
          setInputError(!value);
          setValue(value);
        }
      
        return <TextField
          placeholder={input}
          required
          value={inputValue}
          onChange={onChange}
          helperText={inputError && helperText}
        />
      }
      
      export default function App() {
        const arrObj = [
          {
            name: "Name",
            input: "Please enter your name",
            helperText: "*Name is Required"
          },
          {
            name: "Email",
            input: "enter your email address",
            helperText: "*Email is Required"
          }
        ];
      
        return (
          <div className="App">
            {arrObj.map((item, index) =>
                <Grid key={index} item xs={12} style={{ textAlign: "center" }}>
                  <RequiredTextField item={item} value="" />
                </Grid>
            )}
          </div>
        );
      }
      
      

      请注意,我不使用材质 UI。确保你没有重新发明轮子。我会很惊讶这还不是一个功能。

      【讨论】:

      • 谢谢。一个小建议, const [inputError, setInputError] = useState(true);每当组件呈现时显示错误。所以我觉得应该是假的
      • 是的,我认为如果用户只知道事后需要该字段,那么它对用户不友好。但这是因为您的错误是“礼貌的”,实际上看起来更像是提示。坦率地说,我更喜欢这个。如果他们是大胆的、红色的和讨厌的,我会把它设置为假的。这可以看作是一个症状,如果你坚持在事后显示一些东西,你应该既有提示又有错误。这完全取决于您希望如何与用户交流。
      • 好吧,你所说的也是一个好方法。只有当任何事情失败时才应该显示错误。正如你所说,这些只是提示。谢谢:)
      【解决方案4】:
      import { Grid, TextField } from "@material-ui/core";
      import { useState } from "react";
      import "./styles.css";
      
      export default function App() {
        const [name, setName] = useState("");
        const [email, setEmail] = useState("");
        const [mobile, setMobile] = useState("");
        let inputErrors = {
          name: !name && "Name is Required",
          email: !email && "Email is Required",
          mobile: !mobile && "Phone No is Required"
        };
        const handleChange = ({ target }, setValue) => setValue(target.value);
        const arrObj = [
          {
            name: "Name",
            input: "Please enter your name",
            onChange: (event) => handleChange(event, setName),
            helperText: inputErrors.name && "*Name is Required"
          },
          {
            name: "Email",
            input: "enter your email address",
            onChange: (event) => handleChange(event, setEmail),
            helperText: inputErrors.email && "*Email is Required"
          },
          {
            name: "Mobile",
            input: "enter your mobile number",
            onChange: (event) => handleChange(event, setMobile),
            helperText: inputErrors.mobile && "*Phone No is Required"
          }
        ];
      
        return (
          <div className="App">
            {arrObj.map((item, index) => {
              let { onChange, input, helperText } = item;
              return (
                <Grid key={index} item xs={12} style={{ textAlign: "center" }}>
                  <TextField
                    name={item.name.toLowerCase()}
                    placeholder={input}
                    required
                    onChange={(event) => onChange(event, index)}
                    helperText={helperText}
                  />
                </Grid>
              );
            })}
          </div>
        );
      }
      

      您可以创建一个依赖于状态的变量,而不是多个状态。 这就是我在这段代码中实现的。 另外,我认为它看起来更具可读性。

      Ps:我是第一次在 Stackoverflow 上回答,如果有任何问题,我很抱歉

      【讨论】:

        猜你喜欢
        • 2021-04-18
        • 2019-08-13
        • 2021-08-07
        • 1970-01-01
        • 1970-01-01
        • 2015-09-20
        • 1970-01-01
        • 1970-01-01
        • 2018-03-09
        相关资源
        最近更新 更多