Antonio Pavicevac-Ortiz
Antonio Pavicevac-Ortiz

Reputation: 7739

React: this.setState not resetting state

I have some data I'm distilling to render, essentially I'd like to have a checkbox to reset the state and DOM as it would when the page loads.

Initially I had a selected property on the state and a conditional to make sure it was working. That worked. But I can't get it to work, what am I missing?

UPDATE May 9th 2018

As Jay suggested below I am going to put the whole module in a snippet and focus on the parts which are the crux of the question/problem,

The whole module is in a snippet below...

I have a component that displays an array of objects, and each object is getting distilled into its own card. Below is a screenshot for clarity.

enter image description here

Here is my method in my component:

handleReset() {
    this.setState({
      data: this.props.data,
    });
  }

And this is the JSX which is being rendered.

<label>
  <input type="checkbox" onChange={this.handleReset} />
  <b>reset</b>
</label>

With some time to think about this I realize that my handeReset is not doing anything is probably because it is just rendering the state as it is now. So how my question is how do you go back to the way the UI looked initially? Pre sorting?

import React, {
  Component
} from 'react';
import {
  Card,
  Select,
  Segment,
  Container,
  Divider,
  Grid,
  Header,
  Image
} from 'semantic-ui-react';
import '../css/app.css';

class FilterOptions extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: this.props.data,
      priority: '',
      category: '',
      selected: false,
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleReset = this.handleReset.bind(this);
  }

  handleReset() {
    this.setState({
      data: this.state.data,
    });
  }

  handleChange(e) {
    var val = e.target.value;
    if (!isNaN(val)) {
      this.setState({
        priority: val
      });
    } else if (isNaN(val)) {
      this.setState({
        category: val
      });
    }
    this.props.changeOption(val);
  }

  render() {
    var reset;
    if (!this.state.data) {
      reset = 'reset';
    } else {
      reset = 'not reset';
    }
    return ( <
      div >
      <
      h5 > By category < /h5> <
      label >
      <
      input type = "checkbox"
      onChange = {
        this.handleReset
      }
      />
      reset {
        reset
      } <
      /label> <
      h5 > By category < /h5> <
      ul >
      <
      li >
      <
      label >
      <
      input type = "radio"
      value = "cat1"
      checked = {
        this.state.category === 'cat1'
      }
      onChange = {
        this.handleChange
      }
      />
      cat1 <
      /label> <
      /li> <
      li >
      <
      label >
      <
      input type = "radio"
      value = "cat2"
      checked = {
        this.state.category === 'cat2'
      }
      onChange = {
        this.handleChange
      }
      />
      cat2 <
      /label> <
      /li> <
      li >
      <
      label >
      <
      input type = "radio"
      value = "cat3"
      checked = {
        this.state.category === 'cat3'
      }
      onChange = {
        this.handleChange
      }
      />
      cat3 <
      /label> <
      /li> <
      /ul> <
      h5 > By priority < /h5> <
      ul >
      <
      li >
      <
      label >
      <
      input type = "radio"
      value = "1"
      checked = {
        this.state.priority === '1'
      }
      onChange = {
        this.handleChange
      }
      />
      1 <
      /label> <
      /li> <
      li >
      <
      label >
      <
      input type = "radio"
      value = "2"
      checked = {
        this.state.priority === '2'
      }
      onChange = {
        this.handleChange
      }
      />
      2 <
      /label> <
      /li> <
      li >
      <
      label >
      <
      input type = "radio"
      value = "3"
      checked = {
        this.state.priority === '3'
      }
      onChange = {
        this.handleChange
      }
      />
      3 <
      /label> <
      /li> <
      li >
      <
      label >
      <
      input type = "radio"
      value = "4"
      checked = {
        this.state.priority === '4'
      }
      onChange = {
        this.handleChange
      }
      />
      4 <
      /label> <
      /li> <
      /ul> {
        /*<h5>By Color</h5>
                    <ul>
                      <li>
                        <label>
                          <input type="radio" value="Orange" checked={this.state.color === 'Orange'} onChange={this.handleChange} />
                          <div className="circle orange-filter-bg" />
                        </label>
                      </li>
                      <li>
                        <label>
                          <input type="radio" value="Green" checked={this.state.color === 'Green'} onChange={this.handleChange} />
                          <div className="circle green-filter-bg" />
                        </label>
                      </li>
                      <li>
                        <label>
                          <input type="radio" value="Blue" checked={this.state.color === 'Blue'} onChange={this.handleChange} />
                          <div className="circle blue-filter-bg" />
                        </label>
                      </li>
                      <li>
                        <label>
                          <input type="radio" value="Purple" checked={this.state.color === 'Purple'} onChange={this.handleChange} />
                          <div className="circle purple-filter-bg" />
                        </label>
                      </li>
                    </ul>*/
      } <
      /div>
    );
  }
}

function FilterUsers(props) {
  return ( <
    Container >
    <
    br / >
    <
    br / >
    <
    Grid columns = {
      3
    }
    doubling stackable > {
      props.data.map((user /* leveraging arrow functions implicit return */ ) => ( <
        Grid.Column key = {
          user.name
        } >
        <
        Segment className = {
          `priority${user.priority}`
        } >
        <
        Card >
        <
        Card.Content >
        <
        Card.Header >
        <
        h2 > name: {
          user.name
        } < /h2> <
        /Card.Header> <
        Card.Meta >
        <
        span className = "card__age" > age: {
          user.age
        } < /span> <
        /Card.Meta> <
        Card.Description > priority: {
          user.priority
        } < /Card.Description> <
        Card.Description className = "card__catergory" > category: {
          user.category
        } < /Card.Description> <
        /Card.Content> <
        /Card> <
        /Segment> <
        /Grid.Column>
      ))
    } <
    /Grid> <
    /Container>
  );
}

export default class SortAndFilterForm extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: this.props.data,
      priority: '',
      category: '',
    };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(val) {
    if (!isNaN(val)) {
      this.setState({
        priority: val
      });
      var filteredByPriority = this.props.data.filter(function(item) {
        return parseInt(item.priority) === parseInt(val);
      });
    } else {
      this.setState({
        category: val
      });
      var filteredByPriority = this.props.data.filter(function(item) {
        return item.category === val;
      });
      this.setState({
        category: val
      });
    }

    console.log('filteredByPriority', filteredByPriority);
    this.setState({
      data: filteredByPriority
    });
  }
  render() {
    return ( <
      Container >
      <
      h1 > Sorts < /h1> <
      FilterOptions data = {
        this.state.data
      }
      changeOption = {
        this.handleChange
      }
      /> <
      FilterUsers data = {
        this.state.data
      }
      /> <
      /Container>
    );
  }
}

Upvotes: 2

Views: 1704

Answers (3)

Jay Allen
Jay Allen

Reputation: 485

If I were you, I would turn FilterOptions into a purely functional component (e.g accepts only props, has no constructor, no state, move handleReset and handleChange upwards to SortAndFilterForm and pass them back down via props).

In SortAndFilterForm's constructor(), I would store a copy of its initial state data element (which has been passed to it as props.data from something else) as a state variable (n.b. Object.assign creates a shallow shallow copy which seems like it should work here but it depends on the contents and how you mutate them elsewhere):

this.state = {
  data: props.data,
  initData: Object.assign({}, props.data),
  priority: '',
  category: ''
}

The handleReset method in SortAndFilterForm's would then look like this:

handleReset() {
  this.setState({
    data: Object.assign({}, this.state.initData)
  })
}

You will of course need to bind that in SortAndFilterForm's constructor():

this.handleReset = this.handleReset.bind(this)

...and pass it down to FilterOptions:

    <FilterOptions
        data={this.state.data}
        changeOption={this.handleChange}
        resetOption={this.handleReset}   />

I believe all of the above should take care of your problem.

Upvotes: 0

Anuradha Kulkarni
Anuradha Kulkarni

Reputation: 259

Your HandleReset() method should be setting everything in state as it was at the start:

this.state = {
      data: this.props.data,
      priority: '',
      category: '',
    };

And your cards are rendered with props.data.map meaning they would remain unaffected with changes in state. You should use data from state to render them out.

Upvotes: 1

dave
dave

Reputation: 64657

I am guessing the issue is here:

handleReset() {
  this.setState({
    data: this.state.data,
  });
}

where you set the state.data to state.data, which unsurprisingly doesn't change anything. I imagine you want to do:

handleReset() {
  this.setState({
    data: this.props.data,
  });
}

Upvotes: 3

Related Questions