代码之家  ›  专栏  ›  技术社区  ›  user172902

有条件地反应呈现

  •  1
  • user172902  · 技术社区  · 7 年前

    现在我得到了它的工作,但我不喜欢的解决办法。我的解决方案是基于这样一个知识,即只有当呈现函数内部的状态发生变化时,组件才会重新呈现(在本例中为this.state.errorMessages)。所以我必须像这样显式地将if条件放在render函数中

    renderError() {
        var errArr = [];
        for (var key in this.state.errorMessages) {
            errArr = [...errArr, ...this.state.errorMessages[key]];
        }
        return (
            <div className="alert alert-danger">
                {errArr.map((err) => {
                    return <p>{err}</p>
                })}
            </div>
        )
    }
    
    renderForm() {
        return (
            <form onSubmit={this.handleRegisterFormSubmit}>
                <div className="form-group">
                    <label>First Name</label>
                    <input type="text" className="form-control" name="name" placeholder="Name" value={this.state.firstName} onChange={this.handleFirstNameChange} required/>
                </div>
                <div className="form-group">
                    <label>Last Name</label>
                    <input type="text" className="form-control" name="lastName" placeholder="Last Name" value={this.state.lastName} onChange={this.handleLastNameChange} required/>
                </div>
                <div className="form-group">
                    <label>Email address</label>
                    <input type="email" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email" value={this.state.email} onChange={this.handleEmailChange} />
                    <small id="emailHelp" className="form-text text-muted">We'll never share your email with anyone else.</small>
                </div>
                <div className="form-group">
                    <label>Password</label>
                    <input type="password" className="form-control" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange}/>
                </div>
                <div className="form-group">
                    <label>Password Confirmation</label>
                    <input type="password" className="form-control" name="password_confirmation" placeholder="Password Confirmation" value={this.state.passwordConfirmation} onChange={this.handlePasswordConfirmationChange}/>
                </div>
                <div>
                    <button type="submit" className="btn btn-primary">Submit</button>
                    <button type="button" className="btn btn-danger" onClick={this.handleCancelClick}>Cancel</button>
                </div>
            </form>
        )
    }
    
    render () {
        if (!this.state.errorMessages) {
            return (
                <div>
                    {this.renderForm()}
                </div>
            )
        } else {
            return (
                <div>
                    {this.renderForm()}
                    {this.renderError()}
                </div>
            )
        }
    }
    

    我真的不喜欢这种方法,因为如果我有更多的条件重新渲染,这可能会变得很糟糕。我希望有一个解决方案,在实际的渲染函数中没有太多的逻辑,并将其提取出来。例如。。。

    renderError() {
        if (!this.state.errorMessages) {
            return;
        }
        var errArr = [];
        for (var key in this.state.errorMessages) {
            errArr = [...errArr, ...this.state.errorMessages[key]];
        }
        return (
            <div className="alert alert-danger">
                {errArr.map((err) => {
                    return <p>{err}</p>
                })}
            </div>
        )
    }
    
    render () {
        <form onSubmit={this.handleRegisterFormSubmit}>
            <div className="form-group">
                <label>First Name</label>
                <input type="text" className="form-control" name="name" placeholder="Name" value={this.state.firstName} onChange={this.handleFirstNameChange} required/>
            </div>
            <div className="form-group">
                <label>Last Name</label>
                <input type="text" className="form-control" name="lastName" placeholder="Last Name" value={this.state.lastName} onChange={this.handleLastNameChange} required/>
            </div>
            <div className="form-group">
                <label>Email address</label>
                <input type="email" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email" value={this.state.email} onChange={this.handleEmailChange} />
                <small id="emailHelp" className="form-text text-muted">We'll never share your email with anyone else.</small>
            </div>
            <div className="form-group">
                <label>Password</label>
                <input type="password" className="form-control" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange}/>
            </div>
            <div className="form-group">
                <label>Password Confirmation</label>
                <input type="password" className="form-control" name="password_confirmation" placeholder="Password Confirmation" value={this.state.passwordConfirmation} onChange={this.handlePasswordConfirmationChange}/>
            </div>
            <div>
                <button type="submit" className="btn btn-primary">Submit</button>
                <button type="button" className="btn btn-danger" onClick={this.handleCancelClick}>Cancel</button>
            </div>
            {this.renderError}
        </form>
    }
    

    这会引发一个错误,因为它抱怨This.renderError应该作为函数调用。但当我把它当作 this.renderError() 错误永远不会呈现,因为当错误返回时不会自动调用它。

    或者,为什么我不能像下面这样做

    render () {
        <div>
            <form onSubmit={this.handleRegisterFormSubmit}>
                ...
            </form>
            {if (this.state.errorMessages) {this.renderError()}}
        </div>
    }
    

    这会引发控制台错误

    未捕获错误:模块生成失败:语法错误:意外标记 (117:13)

    本质上,我正在寻找一种解决方案,在render函数中,当状态发生变化时,我可以轻松地显示整个代码块。在Vue,我可以做

    <form>
        <input type="text">
    </form>
    <div v-if="hasError">
        <div class="alert alert-danger">{{something}}</div>
    </div>
    
    Can I do something as easy as this in React?
    
    2 回复  |  直到 7 年前
        1
  •  2
  •   aquiseb    7 年前

    您可以使用map从对象中提取错误消息。

    下面是React中表单验证和错误的最小示例。理解它的工作原理是很好的,但就我而言,我使用 Formik

    class Test extends React.Component {
        constructor(props) {
            super(props);
            this.state = { errorMessages: {} };
        }
    
        handleRegisterFormSubmit = e => {
            e.preventDefault(); // don't submit the form until we run what's below
            let errorMessages = {};
    
            if (!this.state.lastName) errorMessages.lastName = 'You need to enter your last name';
            // And so on for each field validation
    
            // Do we have errors ?
            if (Object.keys(errorMessages).length > 0) {
                this.setState(errorMessages);
            } else {
                // Submit to server
            }
        };
    
        handleChange = e => {
            this.setState({
                [e.target.name]: e.target.value,
                errorMessages: {
                    ...this.state.errorMessages,
                    [e.target.name]: null // remove the error of this field if it's being edited
                }
            });
        };
    
        render() {
            const errArr = Object.keys(this.state.errorMessages).map(key => this.state.errorMessages[key]);
            return (
                <form onSubmit={this.handleRegisterFormSubmit}>
                    <div className="form-group">
                        <label>Last Name</label>
                        <input type="text" className="form-control" name="lastName" placeholder="Last Name" value={this.state.lastName} onChange={this.handleChange} />
                    </div>
    
                    {/* ... your dom */}
    
                    <div>
                        <button type="submit" className="btn btn-primary">
                            Submit
                        </button>
                        <button type="button" className="btn btn-danger" onClick={this.handleCancelClick}>
                            Cancel
                        </button>
                    </div>
    
                    {errArr.length > 0 && (
                        <div className="alert alert-danger">
                          {errArr.map(err => {
                            return <p>{err}</p>;
                          })}
                        </div>
                    )}
                </form>
            );
        }
    }
    

    另一种不显示alert div的方法是在类名中使用三元运算符,并使用bootstrap的 d-none

    <div className={errArr.length ? "alert alert-danger" : "d-none"}>
        {errArr.map(err => {
            return <p>{err}</p>;
        })}
    </div>
    
        2
  •  2
  •   Abdennour TOUMI    7 年前

    我相信这是一个建筑问题。

    尝试遵循以下做法:

    1-直接在JSX中插入条件语句


    1- 直接在JSX中注入条件语句

    坏的:

    if (!this.state.errorMessages) {
        return (
            <div>
                {this.renderForm()}
            </div>
        )
    } else {
        return (
            <div>
                {this.renderForm()}
                {this.renderError()}
            </div>
        )
    }
    

    好的:

    return <div>
                {this.renderForm()}
                {this.state.errorMessages && this.renderError()}
            </div>
    

    2-使用函数组件呈现JSX而不是对象方法

    坏的:

    class FormComponent {
      // ....
    
      renderError() {
        // Blah blah blah 
        return (
            <div className="alert alert-danger">
                {errArr.map((err) => {
                    return <p>{err}</p>
                })}
            </div>
        )
       }
    
       render() {
         return (
           <div>
             <AnotherComponent />
             {this.renderError()}
          <div/>
         )
       }
    
    }
    

    然后 {this.renderError()}

    class FormComponent {
      // ....
    
       render() {
         return (
           <div>
             <AnotherComponent />
             {<Error />} {/* render it as componet ⚠️*/} 
          <div/>
         )
       }
    
    }
    // Build it as component outside the main component (FormComponent) ⚠️
    function Error(props) { 
        return (
            <div className="alert alert-danger">
                {props.errArr.map((err) => {
                    return <p>{err}</p>
                })}
            </div>
         )
    
     }
    

    我花了两年的时间在企业应用程序的开发上,我也是从Udacity毕业的,我在这里分享我的经验。恭喜!

        3
  •  0
  •   Rudi Jansen van Vuuren    5 年前

    通常会在表示列表的元素中呈现项目,并应用一些样式。如果我们没有任何物品,我们有时也不需要这个包装元素。

    我已经编写了下面的组件,它允许条件呈现。如果条件为false,则不会呈现保持DOM干净的元素。

    export default class If extends Component<{ condition: any }, {}> {
    
        render() {
            return this.props.condition ? this.props.children : <Fragment></Fragment>;
        }
    
    }
    

    <If condition={items.length}>
        <-- item list -->
    </If>