Dan Dan - 5 months ago 104
Javascript Question

Passing Values via Props From React Stateless Child to Parent

CONTEXT

I'm trying to pass input value fields (

conditionTitle
) from a React Stateless child component (
AddConditionSelect
) to the parent component (
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 component is stateful. I do not want to have to set any state in the child component, but still be able to access the input in the parent.

In its current form, I am getting a Warning, that the stateless function components 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 component:

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;

Answer

How 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>
    );
  }
}
Comments