user6906049
user6906049

Reputation:

How to filter array & update state when every click in React

I just wonder something about updating state in React. I'm working on basic "to-do app". I created a list & mapped for each element. The user can add a new element in the list and can change the status of the element.

Now, I want the state to update for every click. For example, when the user clicked the completed button, the state is called list will be contained only completed items. I can do it. But after I update the list, I can't access default list. For example, when the user click the button;

changeView(event) {
let clickStatus = event.target.value
if (clickStatus = 'completed') {
const newList = this.state.list.filter((item) => {
return item.completed
})
this.setState({
this.state.list: newList
})
}

But after this, I can't access the list that contains every item.

This is my code:

class App extends React.Component{
  constructor(props) {
    super(props)
    this.state = {
      list: [
        {
          'text': 'First Item',
          'completed': false
        },
        {
          'text': 'Second Item',
          'completed': false
        },
        {
          'text': 'Third Item',
          'completed': true
        }
      ]
    }
    this.handleStatus = this.handleStatus.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleSubmit(event) {
    event.preventDefault()
    const newItem = {
      'text': this.refs.new.value,
      'completed': false
    }
    this.setState({
      list: this.state.list.concat([newItem])
    })
    this.refs.new.value = ''
  }

  handleStatus(event) {
    const itemText = this.state.list[event.target.value].text
    const itemStatus = this.state.list[event.target.value].completed
    const newItem = {
      'text': itemText,
      'completed': itemStatus ? false : true
    }
    const list = this.state.list
    list[event.target.value] = newItem
    this.setState({
      list
    })
  }

  render() {

    const Item = this.state.list.map((item, index) => {
      return <li onClick={this.handleStatus} className={(item.completed) ? 'done' : 'default'} value={index} status={item.completed}>{item.text}</li>
    })

    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <input type='text' ref='new'></input>
          <button type='submit'>Add</button>
        </form>
        <ul>
          {Item}
        </ul>
        <div>
          <button
            value='all'
            type='submit'>All
          </button>
          <button
            value='completed'
            type='submit'>Completed
          </button>
          <button
            value='pending'
            type='submit'>Pending
          </button>
        </div>
      </div>
    )
  }
}

ReactDOM.render(<App/>, document.getElementById('app'))

Upvotes: 2

Views: 14150

Answers (1)

Bartek Fryzowicz
Bartek Fryzowicz

Reputation: 6674

Instead of updating items list in state on each filter change use state property to decide which items should be displayed during rendering.
State should always store whole list and you should just set state property indicating that completed filter is active:

changeView(event) {
    let clickStatus = event.target.value
    this.setState({
        completedFilter: clickStatus === 'completed' ? true : false
    })
}

and then use this property to filter displayed items in render method:

render() {
    let fileredItems = this.state.list;
    if (this.state.completedFilter) {
        fileredItems = this.state.list.filter((item) => item.completed);
    }
    return (
        ...
        {
            filteredItems.map((item) => {
                //return item node
            })
        }
    );

}

Upvotes: 3

Related Questions