Reputation: 157
I have two react components which are ProgramSearchBox and DualBox which are generic and wrapper components of predefined npm packages AutoSuggest and DualListBox respectively.
My task to achieve is Based on the value from ProgramSearchBox, I have to list the set values in the DualListBox.
So, If user select a Program from ProgramSearchBox, then I will call API by passing the ProgramId and fetch the set of result values and have to bind them in the DualListBox.
I will get the user selected ProgramID from the ProgramSearchBox as a prop in DualBox component render method. How to dispatch an action (call a function) from render function in DualBox component by passing the ProgramId?
If I call a method from render function in DualBox, that is becoming Infinite loop!
Here is DualBox component:
//DualBox.js
class DualBox extends React.Component {
constructor() {
super();
this.state = { selected: [] };
this.onChange = this.onChange.bind(this);
this.options = [ ];
}
onChange(selected) {
selected(selected);
}
updateOptions()
{
console.log("Update Option method called :" + this.props.traineesList );
this.options = [{ value: 'luna', label: 'Moon' }, { value: 'phobos', label: 'Phobos' }];
//this.options = this.props.traineeList.map( (value,id) => )
}
render() {
const {ProgramID} = this.props; // HERE I GET ProgramID AS PROP FROM AN ANOTHER COMPONENT
const {selected} = this.state;
if(ProgramID !== "") // BASED ON THIS ProgramID VALUE, I NEED TO DISPATCH AN ACTION.
{
{this.updateProgramId(ProgramID)} // THIS IS CAUSING INFINITE LOOP
{this.updateOptions}
console.log("Program Id came to dualbox:" +ProgramID);
return <DualListBox options={this.options} selected={selected} onChange={this.onChange}
canFilter
filterCallback={(option, filterInput) => {
if (filterInput === '') {
return true;
}
return (new RegExp(filterInput, 'i')).test(option.label);
}}
filterPlaceholder="Filter..."
/>;
}
else
{
console.log("Program Id didn't come to dualbox");
return <DualListBox options={this.options} selected={selected} onChange={this.onChange}
canFilter
filterCallback={(option, filterInput) => {
if (filterInput === '') {
return true;
}
return (new RegExp(filterInput, 'i')).test(option.label);
}}
filterPlaceholder="Filter..."
/>;
}
}
}
function mapStateToProps(state, ownProps) {
return {
traineesList: state.traineesList
};
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
updateProgramId: bindActionCreators(( {ProgramID}) => dualBoxActions.getTraineesList(ProgramID), dispatch)
};
}
export default connect(mapStateToProps,mapDispatchToProps)(DualBox);
Here is the ProgramSearchBox component:
function renderSuggestion(suggestion) {
return (
<ul>
<li>{suggestion.Program}</li>
</ul>
);
}
class ProgramSearchBox extends React.Component {
constructor(props) {
super(props);
}
render() {
const { value, suggestions, onChange, onSuggestionSelected} = this.props;
const inputProps = {
placeholder: "Look Up",
value,
onChange: (event, { newValue, method }) => {
this.setState({
value: newValue
});
console.log("onChange: " + JSON.stringify(newValue) );
onChange(newValue);
}
};
return (
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={this.props.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.props.onSuggestionsClearRequested}
onSuggestionSelected={
(event, { suggestion, suggestionValue, suggestionIndex, sectionIndex, method }) => {
console.log("onSuggestionSelected: " + JSON.stringify(suggestion) );
onSuggestionSelected(suggestion);
}
}
getSuggestionValue={(suggestion) => suggestion.Program}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
theme={theme}
/>
);
}
}
function mapStateToProps(state, ownProps) {
return {
suggestions: state.results
};
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
onSuggestionsFetchRequested: bindActionCreators(({ value }) => searchActions.getProgramSuggestions(value), dispatch),
onSuggestionsClearRequested: bindActionCreators(() => searchActions.clearSuggestions(), dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(ProgramSearchBox);
Upvotes: 0
Views: 1696
Reputation: 1712
Don't call other functions in render()
method. Render method is responsible only for rendering views, it can be called many times and it should be as pure as possible.
Updated answer (2019-11-21)
Use componentDidUpdate(prevProps)
lifecycle function to react to prop changes.
It will look something like this:
componentDidUpdate(prevProps) {
if (this.props.ProgramID !== '' && prevProps.ProgramID !== this.props.ProgramID) {
this.updateProgramId(this.props.ProgramID)
}
}
Old answer
To do actions depending on props changing, use componentWillReceiveProps(nextProps)
lifecycle function.
It will look something like this:
componentWillReceiveProps(nextProps) {
if (nextProps.ProgramID !== '' && this.props.ProgramID !== nextProps.ProgramID) {
this.updateProgramId(ProgramID)
}
}
After calling this.updateProgramId(ProgramID)
props will update and render method will be called.
More info about ReactJS lifecycle: https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops
Upvotes: 4