Nathan Nathan - 4 months ago 85
React JSX Question

Passing JSX to components vs dangerouslySetInnerHTML

I've been working through react examples, and I've been hacking away building some components. Now I think I maybe running into a fundamental "Brain Fart" regarding component structure and nesting.

What I'm after:

A Input component with Optional Labels and help text.

What I have right now: ( which does work )

Input.js

//...//
var MyInput = React.createClass( {

render: function() {

//...//

var helpText = null;

if( typeof this.props.helpText !== 'undefined' ){
helpText = <p className="help-block" > {this.props.helpText} </p>;
}

return (
<div className={ className }>
<MyLabel showLabel={ this.props.showLabel} htmlFor={ this.props.name }>
{ this.props.title }
</MyLabel>
<input
type={ this.props.type || 'text' }
name={ this.props.name }
onChange={ this.changeValue }
value={ this.getValue() }
checked={ this.props.type === 'checkbox' && this.getValue() ? 'checked' : null }
placeholder={ this.props.title }
/>
<span className='validation-error'>{ errorMessage }</span>
{helpText}
</div>
);
}
});

module.exports = MyInput;


LoginForm.js

//...//

var LoginForm = React.createClass({

// ... //

render: function() {
return (
<Form className=" col-sm-11 col-lg-10 block-center loginFrm" >

<div className="row">
<FrmInput value =""
name="username"
title="Username"
className="col-sm-5"
showLabel={false}
helpText= { <span> Help text with <a href="#"> link </a> </span>}
required />
<FrmInput value =""
type="password"
name="password"
title="Password"
className="col-sm-5"
showLabel={false}
required />

<button type="submit"
className="btn btn-default input-sm "
>
Sign In
</button>

</div>

<div className="row">
<div className="pull-right" >
<FrmCheckbox name="rememberMe"
title="Remember Me"
/>
</div>
</div>

</Form>
);
},

});

module.exports = LoginForm;


Making the label optional was easy. I use a BOOL
showLabel
property on the
<MyInput/>
component and pass that on into the MyLabel component.
showLabel
is assumed TRUE, so the a label is shown unless is set showLabel to false as seen above ( then
<MyLabel/>
just returns NULL ).

I first tried a similar method with a
<help/>
component to add the optional help text after the input inside
<MyInput/>
. Everything worked until I added a link inside the help text. Researching I found
dangerouslySetInnerHTML
as a means to pass HTML content into a component. While testing I also found the code above appears to work also, though I'm not exactly sold on why and how "good" this approach is.

In short it appears I'm just passing JSX objects into my component for rendering. inside
<Form>
(from LoginForm.js ) on the
<FrmInput/>
component there is a property named
helpText
set as follows

helpText= { <span> Help text with <a href="#"> link </a> </span> }


inside the
<MyInput/>
component I'm testing/listening for the
helpText
property and setting it to a variable when found (Again wrapping with JSX)

var helpText = null;

if( typeof this.props.helpText !== 'undefined' ){
helpText = <p className="help-block" > {this.props.helpText} </p>;
}


Then in the Render Method I have
{ helpText }


All in all it looks like I'm just passing javascript objects ( via JSX ) on through untill the final render method. I have not seen the above used in tutorials or documentation, so I'm just looking for a professional opinion.

Is the above "good" practice or how could this better be handled.

Answer

There's nothing 'wrong' with your approach. A few suggestions that can help stream line a bit.

You can shorten this block to a simple inline ternary:

var helpText = null;

if( typeof this.props.helpText !== 'undefined' ){
  helpText = <p className="help-block" > {this.props.helpText} </p>;
}

You can remove the above and in your render replace {helpText} with:

{ this.props.helpText ? this.props.helpText : null }

In form input remove the inline helpText html and move to a variable using parens for the JSX.

const helpTextContent = ( <span> Help text with <a href="#"> link </a> </span> );

Then inline: helpText = { helpTextContent }

Lastly if you're using ES6 you can use the following syntax to make using props less cumbersome:

let { helpText, someOtherProp, anotherProp } = this.props;

Then you can just refer to helpText or someOtherProp directly without the this.prop every time.

Hope that helps!

Comments