5
\$\begingroup\$

I am teaching myself React.js from Facebook with small projects. For this one, I want to know if this was the cleanest, most React-ish way I could have done this.

The basic structure is as follows:

Page
    <h2>
    <h2>
    Form
        Adaptive_Input
            <input><label.adaptive><label>
        Adaptive_Input
            <input><label.adaptive><label>
        Adaptive_Input
            <input><label.adaptive><label>

The two headers display information from the page's state. The first one being a name/random text, and the second being an addition of two numbers. The input below that takes in text and two numbers. It's worth pointing out that the fancy Adaptive Input came from this blog post, though it had to be converted to React. Changes in input is sent back to Page to check for validity and display. If input is valid, it's displayed. If not, the header turns read and a warning appears next to the offending input.

Again, I am just starting to learn React.js, so I am mostly concerned about using it correctly, if it is as clean as it could be, and if there are mix-ins or add ons that can simplify the code. Also I understand that the React developers prefer the flux pattern instead of MV*, what changes would I have to make to this to better support the flux pattern?

JSFiddle

JS:

/**
 * @jsx React.DOM
 */
var Adaptive_Input = React.createClass({ 
    handle_change: function(event_data){
        var new_text = event_data.target.value;//this.refs.input.getDOMNode().value;
        this.props.on_Input_Change(new_text);
    },
    render: function(){
        var cx = React.addons.classSet;
          var classes = cx({                
            'invalid_label': 'invalid_label',
            'invalid': 'invalid',
            'invisible': this.props.validity,
          });
        return (
                <div className='adaptive_placeholder_input_container'>
                    <input 
                        className="adaptive_input"
                        type="text" 
                        required="required" 
                        onChange= {this.handle_change}
                        ref="input"
                    ></input>
                    <label
                        className="adaptive_placeholder"
                        alt={this.props.initial}
                        placeholder={this.props.focused}
                    ></label>
                    <label
                        className={classes}
                    >Value is not a number.</label>
                </div>              
                );
    }
});

var Form = React.createClass({
    render: function(){
        return (
                <form>
                    <Adaptive_Input
                        initial={'Name Input'}
                        focused={'Name Input'}
                        on_Input_Change={this.props.handle_text_input}
                        validity={true}
                    />
                    <Adaptive_Input
                        initial={'Value 1'}
                        focused={'Value 1'}
                        on_Input_Change={this.props.handle_value_1_input}
                        validity={this.props.value_1_valid}
                    />
                    <Adaptive_Input
                        initial={'Value 2'}
                        focused={'Value 2'}
                        on_Input_Change={this.props.handle_value_2_input}
                        validity={this.props.value_2_valid}
                    />
                </form>
                );
    }
});

var Page = React.createClass({
    getInitialState: function(){
        return {
            Name : "No Name",
            Text_Valid: true,
            Value_1 : '0',
            Value_1_Valid: true,
            Value_2 : '0',
            Value_2_Valid: true,
            Display_Value: '0',
        };
    },
    handle_text_input: function(new_text){
        this.setState({
                Name: new_text
            });
    },
    handle_value_1_input: function(new_value){
        new_value = parseInt(new_value);
        if(isNaN(new_value)){
            this.setState({
                Value_1_Valid: false, 
            });
        } else{
            var updated_display = new_value + parseInt(this.state.Value_2);
            updated_display = updated_display.toString();
            this.setState({
                    Value_1: new_value,
                    Value_1_Valid: true,
                    Display_Value: updated_display,
                });
        }
    },
    handle_value_2_input: function(new_value){
        new_value = parseInt(new_value);
        if(isNaN(new_value)){
            this.setState({
                Value_2_Valid: false, 
            });
        } else{
            var updated_display = parseInt(this.state.Value_1) + new_value;
            updated_display = updated_display.toString();
            this.setState({
                    Value_2: new_value,
                    Value_2_Valid: true,
                    Display_Value: updated_display,
                });
        }
    },
    render: function(){
        var display_class = 'invalid';
        if(this.state.Value_1_Valid && this.state.Value_2_Valid){
            display_class = 'valid';
        }
        return(
                <div>
                    <h2>{this.state.Name}</h2>
                    <h2 className={display_class}>Value 1 + Value 2 = {this.state.Display_Value}</h2>
                    <Form
                        handle_text_input={this.handle_text_input}
                        text_valid = {this.state.Text_Valid}
                        handle_value_1_input = {this.handle_value_1_input}
                        value_1_valid = {this.state.Value_1_Valid}  
                        handle_value_2_input = {this.handle_value_2_input}
                        value_2_valid = {this.state.Value_2_Valid}
                    />
                </div>
        );
    }
});

React.renderComponent(<Page />, document.body);

CSS:

.adaptive_placeholder_input_container {
    position: relative;
}

.adaptive_input {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    width: 200px;
    height: 40px;
    border: 3px solid #aaaaaa;
    /*border-radius*/
    -webkit-border-radius: 10px;
    -moz-border-radius: 10px;
    border-radius: 10px;
    margin: 0 0 1em;
    padding: 1em;
    background: #fff;
    resize: none;
    outline: none;
    box-shadow: none;
}

.adaptive_input:focus {
    border-color: #00bafa;
}

.adaptive_input:focus + .adaptive_placeholder:before {
    color: #00bafa;
}

.adaptive_input:focus + .adaptive_placeholder:before, .adaptive_input:valid + .adaptive_placeholder:before {
    /*transition-duration*/
    -webkit-transition-duration: .2s;
    -moz-transition-duration: .2s;
    -o-transition-duration: .2s;
    transition-duration: .2s;
    /*transform*/
    -webkit-transform: translate(0, -16px) scale(0.9, 0.9);
    -moz-transform: translate(0, -16px) scale(0.9, 0.9);
    -ms-transform: translate(0, -16px) scale(0.9, 0.9);
    -o-transform: translate(0, -16px) scale(0.9, 0.9);
    transform: translate(0, -16px) scale(0.9, 0.9);
}

.adaptive_input:invalid + .adaptive_placeholder:before {
    content: attr(alt);
    box-shadow: none;
}

.adaptive_input + .adaptive_placeholder {
    pointer-events: none;
    line-height: 1em;
    position: absolute;
    left: 10px;
    top: 10px;
}

.adaptive_input + .adaptive_placeholder:before {

    content: attr(placeholder);
    display: inline-block;
    padding: 0 2px;
    color: #898989;
    /*transition*/
    -webkit-transition: 0.3s ease-in-out;
    -moz-transition: 0.3s ease-in-out;
    -o-transition: 0.3s ease-in-out;
    transition: 0.3s ease-in-out;
    background-color: #ffffff;
}


.valid{
    color: #3472F7
}

.invalid{
    color: #FF3B30 
}

.invalid_label{
    display: inline-block;
    margin: 5px;
    font-family: Verdana, Geneva, sans-serif;
}

.invisible{
    display: none;
}
\$\endgroup\$
0
1
\$\begingroup\$

The only think that I can see right off the bat is your input tags and your label tags

                <input 
                    className="adaptive_input"
                    type="text" 
                    required="required" 
                    onChange= {this.handle_change}
                    ref="input"
                ></input>
                <label
                    className="adaptive_placeholder"
                    alt={this.props.initial}
                    placeholder={this.props.focused}
                ></label>
                <label
                    className={classes}
                >Value is not a number.</label>

The input tags have attributes for setting default text inside the input element so they should be self closing tags.

The label tags also have attributes for the text inside of the label, so you could make these self closing tags as well.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.