CONTEXT
I'm trying to pass input value fields (conditionTitle
) from a React Stateless child ponent (AddConditionSelect
) to the parent ponent (AddConditionDashboard
) that will hold my state.
PROBLEM
I followed the model shown in the React documentation, but they are using refs, which only works if the ponent is stateful. I do not want to have to set any state in the child ponent, but still be able to access the input in the parent.
In its current form, I am getting a Warning, that the stateless function ponents cannot be given refs, resulting in props being null and undefined.
Parent Component:
import AddConditionSelect from '../containers/AddConditionSelect.js';
class AddConditionDashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
conditionTitle: '',
conditionType: ''
};
}
handleUserInput({conditionTitleInput}) {
this.setState({
conditionTitle:conditionTitle
})
}
render() {
const {error, segmentId} = this.props;
return (
<div>
<AddConditionSelect segmentId={segmentId} conditionTitle={this.state.conditionTitle} onUserInput={this.handleUserInput} />
<PanelFooter theme="default">
<Button backgroundColor="primary" color="white" inverted={true} rounded={true} onClick={(event) => this.onSubmit(event)}>
Next Step
</Button>
</PanelFooter>
</div>
);
}
}
export default AddConditionDashboard;
Child ponent:
class AddConditionSelect extends React.Component {
onInputChange: function() {
this.props.onUserInput(
this.refs.conditionTitleInput.value,
)
},
render() {
const {error} = this.props;
return (
<div>
<Panel theme="info">
<Divider />
Please enter a name {error ? <Message inverted={true} rounded={true} theme="error">{error}</Message> : null}
<Input value={this.props.conditionTitle} ref="conditionTitleInput" label="" type="text" buttonLabel="Add Condition" name="add_segment" onChange={this.onInputChange} placeholder="Condition Title"/>
</Panel>
</div>
);
}
}
export default AddConditionSelect;
CONTEXT
I'm trying to pass input value fields (conditionTitle
) from a React Stateless child ponent (AddConditionSelect
) to the parent ponent (AddConditionDashboard
) that will hold my state.
PROBLEM
I followed the model shown in the React documentation, but they are using refs, which only works if the ponent is stateful. I do not want to have to set any state in the child ponent, but still be able to access the input in the parent.
In its current form, I am getting a Warning, that the stateless function ponents cannot be given refs, resulting in props being null and undefined.
Parent Component:
import AddConditionSelect from '../containers/AddConditionSelect.js';
class AddConditionDashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
conditionTitle: '',
conditionType: ''
};
}
handleUserInput({conditionTitleInput}) {
this.setState({
conditionTitle:conditionTitle
})
}
render() {
const {error, segmentId} = this.props;
return (
<div>
<AddConditionSelect segmentId={segmentId} conditionTitle={this.state.conditionTitle} onUserInput={this.handleUserInput} />
<PanelFooter theme="default">
<Button backgroundColor="primary" color="white" inverted={true} rounded={true} onClick={(event) => this.onSubmit(event)}>
Next Step
</Button>
</PanelFooter>
</div>
);
}
}
export default AddConditionDashboard;
Child ponent:
class AddConditionSelect extends React.Component {
onInputChange: function() {
this.props.onUserInput(
this.refs.conditionTitleInput.value,
)
},
render() {
const {error} = this.props;
return (
<div>
<Panel theme="info">
<Divider />
Please enter a name {error ? <Message inverted={true} rounded={true} theme="error">{error}</Message> : null}
<Input value={this.props.conditionTitle} ref="conditionTitleInput" label="" type="text" buttonLabel="Add Condition" name="add_segment" onChange={this.onInputChange} placeholder="Condition Title"/>
</Panel>
</div>
);
}
}
export default AddConditionSelect;
Share
Improve this question
asked May 31, 2016 at 20:00
DanDan
5891 gold badge6 silver badges20 bronze badges
2
- 1 can you show us your Input ponent? That would help. – QoP Commented May 31, 2016 at 20:09
- The input ponent is just a Rebass ponent - jxnblk./rebass/#Input – Dan Commented May 31, 2016 at 20:12
2 Answers
Reset to default 6How about passing the event handler directly to <Input>
? This way you pass the on change event directly to your parent (grandparent of <Input>
) and you can extract the value from event.target.value
so no need to use refs:
Note: You might have to bind
the context of onUserInputChange()
in you parent's constructor because event handlers have the element on which the event happened as their context by default:
Parent
class AddConditionDashboard extends React.Component {
constructor(props) {
// ...
// bind the context for the user input event handler
// so we can use `this` to reference `AddConditionDashboard`
this.onUserInputChange = this.onUserInputChange.bind(this);
}
onUserInputChange({ target }) {
const { value: conditionTitle } = target;
this.setState({
conditionTitle
});
}
render() {
// ...
<AddConditionSelect segmentId={segmentId}
conditionTitle={this.state.conditionTitle}
onUserInputChange={this.onUserInputChange} // <-- pass event handler to child that will pass it on to <Input>
/>
// ...
}
// ...
Child:
class AddConditionSelect extends React.Component {
render() {
const { error } = this.props;
return (
<div>
// ...
<Input value={this.props.conditionTitle}
label=""
type="text"
buttonLabel="Add Condition"
name="add_segment"
onChange={this.props.onUserInputChange} // <-- Use the grandparent event handler
placeholder="Condition Title"
/>
// ...
</div>
);
}
}
- You don't need ref. value can be extracted from the event. Thus, you children ponent bees simpler.
You can simplify your code further using the value link pattern.
class AddConditionDashboard extends React.Component { constructor(props) { super(props);
this.state = { conditionTitle: '', conditionType: '' };
}
render() { const {error, segmentId} = this.props;
return ( <div> <AddConditionSelect segmentId={segmentId} conditionTitle={ Link.state( this, 'conditionTitle' ) } /> <PanelFooter theme="default"> <Button backgroundColor="primary" color="white" inverted={true} rounded={true} onClick={(event) => this.onSubmit(event)}> Next Step </Button> </PanelFooter> </div> );
}
}
export default AddConditionDashboard;
And child ponent
const AddConditionSelect = ({ error, valueLink }) => (
<div>
<Panel theme="info">
<Divider />
Please enter a name { error ?
<Message inverted={true} rounded={true} theme="error">
{error}
</Message> : null }
<Input value={ valueLink.value }
onChange={ e => valueLink.set( e.target.value ) }
label="" type="text"
buttonLabel="Add Condition" name="add_segment"
placeholder="Condition Title"/>
</Panel>
</div>
);
export default AddConditionSelect;