React JS:可重用的组件

时间:2016-03-26 18:26:30

标签: javascript reactjs babeljs

我使用类似

的结构创建了表单验证
par(pin=c(5, 3), lwd=2, cex=1.5)

因为,例如,“电子邮件”输入将用于应用程序的不同部分,我将避免每次添加相同的属性(名称,类型,labelName,规则和错误)。所以我会创建像这样的东西

var Signin = React.createClass({

    render: function() {

        return (
                <Form>
                    <Input type="text" name="email" labelName="Email" rules="isEmail" error:"Email not valid" />
                    <Input type="password" name="password" labelName="Password" rules="isLength:6" error:"Passowrd not valid"/>
                </Form>
        );
    }
});

所以Signin组件应该是

var InputEmail = React.createClass({

    render: function () {

        return (
            <Input type="text" name="email" labelName="Email" rules="isEmail" error="Email not valid"/>
        )
    }
});

var InputPassword = React.createClass({

    render: function () {

        return (
            <Input type="password" name="password" labelName="Password" rules="isLength:6" error="Passwordnot valid"/>
        )
    }
});

但是这样,我得到两个错误:

  1. 我在Form中找不到输入的props.name了 在InputEmail中没有;

  2. 在输入的渲染函数中,状态为空

  3. 我如何创建可重用/继承组件?我没有使用合成模式和mixins

    我添加了完整的代码:Form

    var Signin = React.createClass({
    
        render: function() {
    
            return (
                    <Form>
                        <InputEmail />
                        <InputPassword />
                    </Form>
            );
        }
    });
    

    输入

    var Form = React.createClass({
    
        getInitialState: function () {
            return {
                isValid : false,
                isSubmitting: false
            }
        },
    
        componentWillMount: function(){
            this.model = {};
            this.inputs = {};
            this.registerInputs(this.props.children);
    
        },
    
        registerInputs: function(children){
    
    
            React.Children.forEach(children, function (child) {
    
    
                if (child.props.name) {
    
    
                    child.props.attachToForm = this.attachToForm;
    
                    child.props.detachFromForm = this.detachFromForm;
    
                    child.props.validate = this.validate;
                }
                if (child.props.children) {
                    this.registerInputs(child.props.children);
                }
            }.bind(this));
        },
    
    
        attachToForm: function (component) {
            this.inputs[component.props.name] = component;
            this.model[component.props.name] = component.state.value;
            this.validate(component);
        },
    
        detachFromForm: function (component) {
            delete this.inputs[component.props.name];
            delete this.model[component.props.name];
        },
    
        validate: function (component) {
    
            var isValid = true;
                    // validation code
            component.setState({
                isValid: isValid,
    
            }, this.validateForm);
    
        },
    
    
        validateForm: function () {
            var formIsValid = true;
    
            var inputs = this.inputs;
            Object.keys(inputs).forEach(function (name) {
                if (!inputs[name].state.isValid) {
                    formIsValid = false;
                }
            });
    
            this.setState({
                isValid: formIsValid
            });
        },
    
        updateModel: function (component) {
            Object.keys(this.inputs).forEach(function (name) {
                this.model[name] = this.inputs[name].state.value;
            }.bind(this));
        },
    
        submit: function (event) {
            event.preventDefault();
    
            this.setState({
                isSubmitting : true
            });
    
            this.updateModel();
            console.log(this.model);
        },
    
        render: function () {
    
            return (
    
                <form className="ui form" onSubmit={this.submit}>
                    {this.props.children}
                    <button className="ui button" type="submit" disabled={this.state.isSubmitting}>Accedi</button>
                </form>
            );
        }
    });
    

    有了这个作品

    var Input = React.createClass({
    
        getInitialState: function(){
            return {
                value : this.props.value || "",
                isValid: true
            }
        },
    
        setValue: function (event) {
    
            this.setState({
                value: event.target.value
            }, function () {
    
                this.props.validate(this);
    
            }.bind(this));
        },
    
        componentWillMount: function () {
    
            if (this.props.required) {
                this.props.validations = this.props.validations ? this.props.validations + ',' : '';
                this.props.validations += 'isLength:1';
            }
    
                    // ERROR: TypeError: this.props.attachToForm is not a function
            this.props.attachToForm(this);
        },
    
        componentWillUnmount: function () {
            this.props.detachFromForm(this);
        },
    
    
        render: function () {
    
            var className = "field";
    
            if(this.props.className){
                className +=  " " + this.props.className;
            }
    
            if(this.props.required){
                className += " required";
            }
    
            var Label;
            if(this.props.labelName){
                Label = (<label htmlFor={this.props.name}>{this.props.labelName}</label>);
            }
    
            var Error;
            if(!this.state.isValid){
                Error = (<div className="ui">{this.props.error || this.props.name + " not valid"}</div>);
            };
    
    
            return (
                <div className={className}>
                    {Label}
                    <input type={this.props.type || "text"} id={this.props.name} name={this.props.name} onChange={this.setValue} value={this.state.value} />
                    {Error}
                </div>
            );
    
        }
    });
    

    通过这种方式我得到: “TypeError:this.props.attachToForm不是一个函数 this.props.attachToForm(本);“

    ReactDOM.render(
        <Form>
            <Input type="text" name="email" labelName="Email" rules="isEmail" error:"Email not valid"/>
        </Form>,
        document.getElementById('app')
    );
    

    P.S:我试图在jsfiddle上添加这个代码,但我得到“!TypeError:无法定义属性”attachToForm“:对象不可扩展”

    jsfiddle

1 个答案:

答案 0 :(得分:0)

您的设置存在两个主要问题:

  1. 您的<Form>是以这样的方式设置的,表单中的孩子需要有道具,否则它不起作用。
  2. <InputEmail>包装器不完整。它需要将所有道具传递给<Input>,包括传递下来的Form函数。
  3. 广告1:修复表单,确保添加验证方法
    您收到错误的原因是您的<Form>的孩子需要拥有props.name。然后通过将它们添加到子项中来注册表单的函数(包括attachToForm)。这是在registerInputs()方法中完成的。

    在原始版本中,<Input>组件有道具,所以一切顺利。

    在改编后的变体中,包装器<InputEmail>不再具有道具,因此attachToForm()和其他功能不会添加到道具中,并且当<Input>尝试使用时会出现错误调用函数。

    解决此问题的最简单方法:在渲染函数中添加至少1个道具,并在registerInputs()中进行检查,例如:

    ReactDOM.render(
        <Form>
            <InputEmail initialValue={'name@domain.com'}/>
        </Form>,
        document.getElementById('app')
    );
    

    registerInputs()中,更改行:

    if (child.props.name) {
    

    为:

    if (child.props.initialValue) {
    

    <强> 2。扩展<InputEmail>包装器以传递函数
    最简单的方法是添加{...this.props},如下所示:

    var InputEmail = React.createClass({
    
        render: function () {
    
            return (
                <Input {...this.props}
                  type="text" name="email" labelName="Email" rules="isEmail" error="Email not valid"/>
            )
        }
    });
    

    这样,<Form>传递给<InputEmail>组件(以及任何其他道具)的函数将传递给<Input>组件。

    PS:检查child.props.children的registerInputs()内的代码无法正常工作:在调用它时,<InputEmail>组件没有子代。顾名思义,它会检查作为道具传下来的孩子。通过的唯一道具是initialValue

    作为小问题,我建议再做2次更改:

    1. registerInputs()中,您可以直接修改道具。这通常不是一个好主意。更好的是制作道具的副本,并将您的表单方法添加到副本中。您可以使用React.Children.map执行此操作。见official docs here
    2. 使用{{1>而不是对name="email"组件的<Input>等进行硬编码,而不是在<InputEmail>内更好地将这些组件的默认值置于道具的默认值中如here in official docs所述。