Refactoring the Date Picker in the React Countdown Project
Welcome back to the course. In the last video, we set up our picker to connect to the app.js with a callback prop in our picker component.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

Now it's printing out the days remaining, but it's printing out twice. Let's get rid of bug first. Let's go into our picker.js, and let's go ahead and get rid of the startDate completely. I'm going to get rid of this log as well. Let's go ahead and get rid of the state, and let's bind this like so:

picker.js

class Picker extends Component {

    handleChange = function(date) {
        this.props.callback(date)
    }.bind(this);

Now by doing this we can get rid of the constructor entirely. Let's go ahead and see if it is still functional. Looks like it says: can not read property 'startDate' null, and that is because of this. So let's go ahead and say:

picker.js

  render() {
    return (
      <div className="picker">
        <DatePicker
          selected={this.props.startDate}
          onChange={this.handleChange}
        />
      </div>
    );
  }

Now we can go into app.js, and we can say:

app.js

  renderItems = function() {
    if(this.state.active) {
      return [
        <Clock/>,
        ChangeDate('Change Date', () => this.setState({ active: false })),
        LargeText('04/03'),
        <label className="grid__remaining">Remaining until your 21st birthday</label>
      ]
    } else {
      return [
        <Picker startDate={this.state.startDate} callback={(date) => this.handleChange(date)}/>,
        Button('Generate Countdown', () => this.handleGenerate())
      ]
    }
  }.bind(this)

Cool, it's functional. Now, you will see that if we select a day in the future, let's say 1 day in the future, it only prints out that date now.

large

Let's go ahead and get this in here now, because we clearly want it in here, not just in the console. We have this handleGenerate function and it's running, obviously, because we are printing it, but we aren't setting it anywhere. We're just logging it.

So let's do this: let's take these days, hours, minutes, and seconds, and put it in an object in our state so we can get access to them elsewhere such as in our clock component. Let's head up to our constructor, let's put a comma here, and let's make an object.

app.js

constructor(props) {
    super(props)

    this.state = {
      active: false,
      startDate: moment(),
      timeRemaining: {
        days: 0,
        hours: 0, 
        minutes: 0,
        seconds: 0
      }
    }

Now what we can do is set this. So what I want to do is just copy this entirely, this time remaining object, and let's go down here where we are logging it. Let's say:

app.js

    const time = days + "d " + hours + "h " + minutes + "m " + seconds + "s ";
    console.log(time)
    this.setState({
      timeRemaining: {
        days,
        hours,
        minutes,
        seconds
      }
    })

This should be working, so let's try it out by instead of logging the time let's cut that and put it below here. Then let's log console.log(this.state.timeRemaining);, and see if it is in our state. I'm going to head the application, select a day in the future, and I'm going to hit generate. It says: this.setState is not a function

large

The reason this is not working...interesting, let's see. Let's try this, let's cut this out object out, and let's set it in a variable. Let's say:

app.js

    const time = days + "d " + hours + "h " + minutes + "m " + seconds + "s ";
      const timeRemaining = {
        days,
        hours,
        minutes,
        seconds
      }
      this.setState({ 
        timeRemaining
       })

Let's reload the page, and try it again. It still says that it's not a function. Let's go ahead and instead of setting the state on timeRemaining, let's comment that out, and say: active: this.state.active so that it doesn't change the value of it. We want to see if it is working. Now it says: cannot read property 'active' of undefined.

large

The reason this is strange is because we are indeed binding this function, but for some reason, it's still not working. What I want to do is go in here and say:

app.js

    export default class App extends Component {

    constructor(props) {
        super(props)

        this.state = {
        active: false,
        startDate: moment(),
        timeRemaining: {
            days: 0,
            hours: 0, 
            minutes: 0,
            seconds: 0
        }
        }

        this.handleGenerate = this.handleGenerate.bind(this)
    }

Let's see if that fixes it. We are setting the state up here and it's working. Let's copy this. It could be a typo. I'm going to paste it in here because that's really strange. It should be working. Strange. Okay, so it's the timer. That's what's going on.

This is what we should do, let's not call it x, let's call it timer, and let's get rid of the var here. Let's go up to our constructor, and say:

app.js

    export default class App extends Component {

    constructor(props) {
        super(props)

        var timer = 0;

        this.state = {
        active: false,
        startDate: moment(),
        timeRemaining: {
            days: 0,
            hours: 0, 
            minutes: 0,
            seconds: 0
        }
        }

        this.handleGenerate = this.handleGenerate.bind(this)
    }

For now, let's try this. It's not working. Let's just set state out of the timer, well that wouldn't because we need it to constantly be updating the timeRemaining. What I want to do is end the video here, and then we'll solve it in the next video so we can move on quicker.

Let's commit our code. Let's say git status, git add ., and let's say git commit -m "cleaned up picker.js". See you in the next video.

Resources