Building a state based on props can be a bit complicated, which is acceptable, but you should consider all your options.
The easiest to implement is filtering props in your render method. If you have small enough components that are not updated for too many reasons, especially if the number of items in the list is small, this may be the preferred method:
class FilterList extends React.Component { render () { const { elements } = this.props; const { filterStr } = this.state; const filteredElements = elements .filter(e => e.includes(filterStr)) .map(e => <li>{ e }</li>) return ( <div> <input type="text" value={ filterStr } onChange={ e => this.setState({ filterStr: e.target.value }) } /> <ul> { filteredElements } </ul> </div> ); } }
The next option is to do what you are describing and get the calculated state based on the state of the component filter and its missing details. This is good when you have a complex component that receives many details and is often displayed. Here you cache visible elements and filter the list only when you need to filter it.
class FilterList extends React.Component { constructor (props) { this.state = { viewableEls: props.elements } } componentWillReceiveProps (nextProps) { const { elements } = this.props; const { filterStr } = this.state; if (elements !== nextProps.elements) { this.setState({ viewableEls: this.getViewableEls(nextProps.elements, filterStr) }) } } getViewableEls (elements, filterStr) { return elements.filter(el => el.includes(filterStr)) } handleFilterChange = e => { const { elements } = this.props; this.setState({ filterStr: e.target.value, viewableEls: this.getViewableEls(elements, filterStr) }) } render () { const { viewableEls } = this.state; return ( <div> <input type="text" value={ filterStr } onChange={ this.handleFilterChange } /> <ul> { viewableEls.map(e => <li key={ e }>{ e }</li>) } </ul> </div> ); } }
And finally, the βpathβ for filterStr , which requires you to pass the action creator and filterStr as the props for the component, was probably passed through connect somewhere else. The implementation below uses the stateless component, since we are not fitlerStr in the state of the component at all.
const FilterTable = ({ elements, filterStr, changeFilterStr }) => { return ( <div> <input type="text" value={ filterStr } onChange={ e => changeFilterStr(e.target.value) } /> <ul> { elements .filter(e => e.includes(filterStr)) .map(e => <li key={ e }>{ e }</li>) } </ul> </div> ) }
Nathan hagen
source share