I have an array of objects stored in redux. I want to be able to filter that array based on user input. Should I create a state object that receives the array through props and modify that array, or is it bad practice to mix state and props? If it is alright to mix the two, should I set the state in componentWillReceiveProps?
To filter an array of objects in React:Call the filter() method on the array. On each iteration, check if a certain condition is met. The Array. filter methods returns an array with all elements that satisfy the condition.
Building state based on props can be somewhat complicated, which is acceptable, but you should consider all of your options.
The simplest to implement is to filter the props in your render
method. If you have sufficiently small components which don't update for too many reasons, and especially if the number of elements in the list is low, this might 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're describing, and derive a computed state based of the component's filter state and props passed to it. This is good when you have a complicated component which recieves many props and is rendered often. Here, you're caching the viewable elements and only filtering the list when it needs to be filtered.
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 redux 'way', which requires you to pass the action creator and filterStr
as props to the component, probably passed in via connect
somewhere else. The implementation below is using a stateless component since we're not keeping the fitlerStr
in the component state 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>
)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With