Following is my code (which is working fine) in which I am able to sort list on the basis of input provided in text box. In constructor
method I declared my states like this -
this.state = {
data: ["Adventure", "Romance", "Comedy", "Drama"],
tableData: []
};
In componentDidMount
method I assign the data
key state in tableData
.
componentDidMount() {
this.setState({
tableData: this.state.data
});
}
My question is - Is it the correct way of doing this as somehow I myself not feeling confident about this code quality (Initializing the tableData as []
and then setting tableData: this.state.data
in componentDidMount
method ). Let me know if I can improve this also what will change if I fetch
the data from an API which is the best place to initialize and use in an app.
Working Code Example - https://codesandbox.io/s/k9j86ylo4o
Code -
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: ["Adventure", "Romance", "Comedy", "Drama"]
};
this.handleChange = this.handleChange.bind(this);
}
refineDataList(inputValue) {
const listData = this.state.data;
const result = listData.filter(item =>
item.toLowerCase().match(inputValue.toLowerCase())
);
this.setState({
data: result
});
}
handleChange(e) {
const inputValue = e && e.target && e.target.value;
this.refineDataList(inputValue);
}
render() {
return (
<div className="App">
<h3>DATA SEARCH</h3>
<div className="form">
<input type="text" onChange={this.handleChange} />
</div>
<div className="result">
<ul>
{this.state.data &&
this.state.data.map((item, i) => {
return <li key={i}>{item}</li>;
})}
</ul>
</div>
</div>
);
}
}
You are doing great, but you are right there is a way to do it in better way, handle two point of truth is difficult to maintain, so you should have only one data array with the words that you need, so the way you should filter the values is by creating a filter
variable into state to store the current word to be filtered, so you should add something like
// in the constructor function
constructor(props) {
super(props);
this.state = {
data: ["Adventure", "Romance", "Comedy", "Drama"],
filter: ""
}
}
// create a filter function
getFilteredResults() {
const { filter, data } = this.state;
return data.filter(word => String(word).toLowerCase().match(filter));
}
// and finally into your render function
render() {
return (
<div>
{this.getFilteredResults().map((word) => (
<div>{word}</div>
))}
</div>
);
}
Obviously remember to update your handleChange
function, like so
handleChange(e) {
const inputValue = e && e.target && e.target.value;
this.setState({ filter: inputValue });
//this.refineDataList(inputValue);
}
In that way you will maintain only one point of truth, it will work as expected.
Note: we use String(word).toLowerCase()
to ensure that the current word
is actually a string
, so we can avoid the toLowerCase is not function of undefined
error, if for some reason word is not a string.