- Read Tutorial
- Watch Guide Video
If you go to Chrome, you'll see that in our console, we are printing out this date once we hit start. Once you hit generate, it's going to start this countdown.
I have two running now because I hit Change Date, and started it again. You can already see that there is a problem that we are going to have to solve in the future. That is stopping the timer once we hit Change Date, so we can restart it rather than starting a whole new one.
Anyway, that is not what this video is going to cover. What this video is going to cover is making this date go into here, and making it so we can console.log the amount of time between now and that the date you put in.
If you put this in, it's actually going to be empty because it's going to be today right? or whatever day you're on. Whatever day it is for you. So what we need to do after we get that functionality in it is
test it by selecting a couple days ahead rather than leaving it on the date is today.
So select a day, like a couple days in advance, after we put in this functionality and then we'll hit generate. We'll see it say something like two days and a couple hours. Let's go ahead and get this functionality in by first closing out all of our files except for picker.js and app.js. I'm also closing the terminal.
Basically, we have our DatePicker in our picker.js, and we need to somehow get access to this piece of state. Now if we were in Redux, this would make it an excellent way to make it so that we don't have to do any refactoring.
It would be an excellent way to have access to this in other files. Since we didn't use the Redux template, and because it would a little advanced in this project, what we are going to do is take a different approach. Let's think of how we can do this.
When I built this application, initially, I did it a completely different way other than the raw logic. I didn't have this many components. I did it in a best practice kind of way, so we're going to try and figure this out on the go. So let's do this. So we just need to get access to the picker start date into our app.js.
We have picker here, we have the button here, and we have the clock here. We don't really want to do anything with the clock except for put in the date, because in clock we don't have the logic for clock in here. We have it in app.js.
There's a couple ways that we could do this. We could get rid of the picker component, and we could just put the state into our application, or we could somehow connect these two components. Pass them back up. Let's see...we are going to want to us props.
Let's go to app.js. We are going to want to pass a props in here, probably a function that will run whenever we set this, and then we will just set the state back up in this application. That seems good, so what I want to do is go to the constructor up here, and let's make a start date and import moment. Let's say:
app.js
import React, { Component } from 'react'; import Picker from './picker'; import Button from './button'; import Clock from './clock'; import ChangeDate from './changeDate'; import LargeText from './largeText'; import moment from 'moment'; export default class App extends Component { constructor(props) { super(props) this.state = { active: false, startDate: moment() } }
That looks good. Now what we want to do is go into our picker.js, and basically, we want to when we handleChange
on this, we want to call a function in our app.js. That we will basically set the state on. What I want to do is just copy this entire function.
Then I want to go to app.js and put it right below our constructor. We also need to bind it, so if you back to picker.js you'll see that it says: this.handleChange = this.handleChange.bind(this);
. You can either copy that and put it in our constructor here, or we can write this function a little differently and learn a new way of binding functions.
This is how you do that. So let's say:
app.js
export default class App extends Component { constructor(props) { super(props) this.state = { active: false, startDate: moment() } } handleChange = function(date) { this.setState({ startDate: date }); }.bind(this)
It's the same exact thing that we're doing here, except for it reduces the need for this line and it's all done right here. It makes a function a little bit more ugly in my opinion, so feel free to do it either way you want either find it here or copy this and put it in a constructor here.
Again, I just want to make it clear that this function has nothing to do with this page. We're just calling it the same thing. Then we are going to call it in our handleChange
in picker.js. That's probably really confusing, but just hang tight, we're going to explain how this works in a second, in detail.
So we have our function, and we have our start date in here. We are going to have access to our date through this function, but we have no way of calling this function yet. We can give us a way of calling this function by going into our picker here and saying something like:
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 callback={this.handleChange}/>, Button('Generate Countdown', () => this.handleGenerate()) ] } }.bind(this)
Now, all we have to do is go to our picker.js, and just say in here:
picker.js
handleChange(date) { console.log('trying to change date for', date._d); this.setState({ startDate: date }); this.props.callback(date) }
Now we are going to have to refactor our props a little bit, so let's go back and 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 callback={(date) => this.handleChange(date)}/>, Button('Generate Countdown', () => this.handleGenerate()) ] } }.bind(this)
There are two functions here. We have our function callback
and it takes in a date, and in that function, it calls the function handleChange
up here which takes in a date. Now, where we are getting this date is in picker.js by saying this.props.callback(date)
. So just kind of go back and forth to make sure you understand this whole flow.
Let's go see if it works. Ignore this error, it has nothing to do with what we are doing right now. It has something to do with we are returning items in our date, so just ignore that for now.
I'm going to click a couple days in advance. Obviously, the time is not going to work because we didn't do anything with the time, so it's going to be logging the same thing, but we'll see if we get any errors by doing this. It looks like we didn't get any errors.
What I want to do now is go back in here into app.js, let's go to our handleChange
function, and let's just console.log
just to make sure it's working. I don't want to say: trying to change date for
because we are doind that in our console.log in handleChange in picker.js.
What I'd rather do is just put a bunch of capital letters or something just so I can kind of tell it's this app. So I'm going to say in app.js, in the handleChange
function, console.log('APP JS HANDLE CHANGE', date._id);
.
That is pretty clear. It's pretty different from this console.log, so we will be able to see that. Let's go to our application and hit generate, and see if we can see it. I'm not seeing it, but at the same time, I'm not really seeing that this function is printing at all.
Let's see...that's because this is the date, so what we need to do is change the date for that to even console.log. So scroll down to the bottom of your output or reload the page, select a date, and you'll see that it is trying to change date for Saturday, June 2nd
. It also says: APP JS HANDLE CHANGE
.
That's pretty cool. That means we're getting the date in our app.js file now, which is exactly what we wanted. Now what we need to do is generate our countdown with this date instead of the countdown date that we see here.
We can do that pretty simply by getting rid of this date object, and saying:
app.js
var countDownDate = this.state.startDate.getTime();
Now we will have access to this start date because we selected a date. If you just hit generate without selecting a date, start date will still be equal to moment
, and it will be the same exact time as new Date().getTime();
. Same thing as moment, just a different library.
Let's try out the first case where we just don't change the date, and you'll see that we get an error:
Let's see. Let's copy this, let's hit command + z
to get back our old code, and then I'm goint to paste it and comment it out, so that we have access to it. Basically what's going on here is we're saying this.state.startDate
. It's a date right? Why can't we time if we can get the time on the date here?
That's because startDate
is a moment. It's not a date. It's using the moment
library. The one that we installed not too long ago. What we need to do is convert it to a date, and then call getTime
. So let's do this. Let's get rid of this again, let's uncomment this, and let's say:
app.js
var countDownDate = this.state.startDate.toDate().getTime();
It might crash. If it does we will check the documentation for moment. Let's hit generate, and it appears to be working. You see how it say's -1d
?
Now what we need to do is try the second case where we choose an actual date. So let's click on here and choose June 2nd or whatever day is a couple days in advance for you. You'll see it sets it, and then when we hit genterate, it prints out 1d 23h 59m 46s
.
Sweet, we selected two days in advance, and now it's counting down two days. Which means if your birthday is September 15th like mine, then you hit generate, you can see there's 106 days until my birthday. Now you see that we're printing out two of these, which is kind of confusing.
We got the functionality for this pretty much complete, at least for the countdown part of it, let's go ahead and commit our code. Then in the next video, we will make a couple bug changes, and see what other problems we are going to run into.
Let's hit command + j
if you are in visual studio code. Let's say git status
, git add .
, and what I'd like to say is git commit -m "refactored app.js and picker.js to have startdate"
. Let's go ahead and move on to the next video. See you then.