Transcripts
1. Introduction: Hi, I'm Hunor, and today I'm going to teach you how to build a Tic-Tac-Toe game with React. If you haven't used React before, don't worry, we are going to cover all the basics of React while we are building this game. First, I'm going to talk about how to break down this game into smaller pieces, into components, and how to connect these components. Then we're going to cover how to make this gaming interactive, what is the state, and how to detect the winner at the end of the game. The only thing you need to have is some prior HTML, CSS, and JavaScript knowledge, and after this course, you are going to be able to build a simple game or a website with React.
2. Breaking Down the Game Into Components: We are going to create our application in React. React is as a component-based library. So first, we have to break down our application into components. But what is a component and how to break down an app? A component is like a function. If you think about it, you mainly write functions for two reasons. One is to break down your application logic into smaller meaningful bits. A function is basically a piece of code with a name. If someone reads that name, hopefully, they would know or at least have a good idea regarding what the function does. The second reason to write a function is to avoid repetition. If you find yourself writing the same lines over and over again, then probably you are going to write a function for that and call it in multiple places instead of repeating the same lines. We are going to do the same thing with components. But before getting there, first, we need an initial component the one that will be injected into HTML and that will serve as a root for all the rest of the application. In our case, this is going to be the TicTacToe component itself. Technically, we can actually stop here. It's not required at all to have multiple components. But usually, if you try to have all your logic in one component together with all the layout information, probably, it's going to be too long and unmaintainable. So let's start breaking down our application by avoiding repetition. There are two very obviously repeating things in this app, the crosses and the circles. There's also a third one, which is not so visual, so it's easy to miss. But if you look a bit closer, then you see that this grid consists of nine squares. And the squares don't have much to show, but you're going to see that their behavior is the same. So they're also going to be a really good candidate for a component. Once we are done with repetition, we can look out for parts of the application that are more or less independent from the rest of the application. In our case, if you play through this game, then you end up on a result screen. Of course, this result screen is not fully independent from the rest of the game because it has to know if the game has finished, who won the game, and how to reset the game. But apart from that, it doesn't have to know every detail. It doesn't have to know what's the status of the second square in the third row. So in this way, it's independent. It could be interpreted as a function with properties. So these are going to be our components, but of course, this is not the only way to break down an application. One way to check if we did a good job is to check the component names. If the component names are meaningful and you can more or less guess what the component does or how does it look like, then there's a good chance that our breakdown is good.
3. Writing Our First Components: Let's start creating things. For this tutorial, we're going to use CodePen, which is a web editor and social media platform. When you create something on CodePen, it's going to be public so other people can see it, can comment on it, can like it, and if it's really good and the editors of the sites see it, then maybe they highlight it and you can see yourself on the front page. If you haven't used CodePen before, then you can just quickly sign up using your Twitter, GitHub or Facebook account. Once you're in, on the top left corner, you're going to see "Create Pen", and this is leading us to the web editor. So this is your editor here, you can edit HTML, CSS, and JavaScript and the great thing about it is once you edit something, then the result will show up in the results screen right away. If you add some simple primary header and paragraph, then you're going to see the result in the result panel. We are going to use React and React is not part of the standard JavaScript. It's an external library. Luckily for us, in CodePen, you can easily add external libraries to a project. Go to Settings, select the JavaScript panel, and search for React. Once you've added React, we also have to add something called ReactDOM and here you have to watch out that the version number of React and version number of ReactDOM have to match. If that's not the case for some reasons, then check out the comment below this video. We have to set one more thing here. We have to set a JavaScript Preprocessor and this is going to be Babel in our case. Regarding what is Babel, why do we need it and what is ReactDOM. I'm going to explain it just in a bit but for now, let's just save this and we are ready to go. Let's write some JavaScript and let's start by creating our very first component. And this may be surprising, but a component is basically a function. When I was saying before that the way you break down an application to a component is the same as breaking down an application logic into functions. Well, components are closer to functions than you might have thought. A component is a special function which is returning something that really looks like HTML. But this is still not HTML, we are still inside JavaScript and you might be wondering how is this working? I mean, this is not JavaScript. You cannot add HTML tags in JavaScript, and the answer to this question is that in fact, we are not using JavaScript here. This is not JavaScript. At least not pure JavaScript. Remember we set Babel as a preprocessor for JavaScript. Babel is transpiling this code into proper JavaScript. In the background we're having proper JavaScript, but we are editing a slightly modified version of JavaScript, which allows us to write HTML tags. Or at least something that really looks like HTML tags. We have a React component, but in the results screen, we still don't see it. This is like having a function which has never been called. We are having a function that is generating a piece of HTML, but we don't say where this generated HTML should belong and it's not added automatically to the root of HTML. We have to define an entry point in HTML. Let's just add a simple div, with an ID, and I'm going to use "app" as an ID, but you can just write any other name if you want. In JavaScript we are going to use ReactDOM. ReactDOM is a really simple utility library and its only purpose is to look up the HTML, find this ID, and replace its content with our component. If you've done everything right, then finally, we have a React component inside our website and that's a really great start. Before we move on to the next section, let's just quickly add the skeleton of the other components that we agreed on. Let's just add a Square component, a Cross component, and the Circle component plus the results screen components. These components for now are going to be very simple components. They are just returning a piece of text and they're not going to be connected with our root components. They are just staying in outer space and not doing anything at all, but this is our application skeleton. We're going to connect these components in our next sections.
4. The Grid: In our previous lessons, we wrote our very first React components. But on our results screen, we still only see "Hello from React" in the top left corner, and we're not even using most of our React components at all. In this lesson, we are going to talk a lot about CSS, how to add style these components, and how to connect them, how to embed the Square component inside the TicTacToe component. First of all, let's center everything. Right now, by default, everything is on the top left corner. And this is a game, this is not a normal website, we want to center everything. To center everything we go to our highest level tag and define some CSS properties for it. The highest level right now is our div inside the HTML, which is the entry point of the application. It already has an ID, so let us just use that inside CSS, and for centering things, we are going to use CSS Flexbox. If you haven't used CSS Flexbox before, it's really good for centering things and aligning things evenly. Right now we're only going to use it for centering, and it has some really weird property names like justify-content and align-items. It's not so intuitive that one is for aligning things horizontally and one is for aligning things vertically, but it works really well. Once we added it, everything should be in the middle of the screen. Well, everything right now is just a text saying, "Hello from React", because that's all what the TicTacToe component is producing. Let's change that. Let's replace this initial text with nine instances of the Square component. You might be wondering how to do so because, TicTacToe component is producing a piece of HTML, Square component is also producing a piece of HTML, but the Square component itself is just a function. So do we make function calls, and do we call the Square components as a function? In React, you can refer to components, as if they were custom HTML tags. Which is really handy because the Square component is needed inside a TicTacToe component's return statement. Now we have nine squares in the TicTacToe component, but they don't appear as a grid. To fix that, we are going to assign some CSS class for the TicTacToe component's main container. And this is something that's slightly different from HTML. As I said before, this is not HTML actually, it just looks like that. This is called JSX, JavaScript XML, and it has some minor differences comparing to HTML. One of them is that you can't use the class keyword, because the class keyword is reserved in JavaScript and has some very different meanings. Instead of writing class, we write className. To align the content in a grid, we are going to use CSS grid. If you haven't used CSS grid before or CSS Flexbox, there's a link below this video which is explaining really well how they work. So with CSS grid, we are defining, that we want to have three columns and three rows, and we want to have some gap in between them. Now it looks a bit better, but the squares don't look like squares at all. The same way as we attached a class for the TicTacToe component, let's attach a square class for the Square component, and let's add some CSS. Here we're fixing the width, and the height of the component, so it will look like a square, and we are also centering the content of the square the same way as we centered the whole application, which CSS Flexbox. Now we have our nine squares in a grid, but we want to have some border in between them. Unfortunately, with CSS grid, we cannot set the border color. We are going to use a little trick here. Instead of setting the border color, we are setting the background color of the whole grid, then setting the Square components background color to the whole application's background color. This way, it looks like we set the border color of the grid, even though we actually didn't.
5. Which Square is Which? : We have our nice-looking grid, but all the squares inside look the same. Just to clarify, which square is which, let's give them a unique ID. In React, you can configure component instances by passing on props to them. A props is something like an attribute to a function. We are going to say it's exactly an attribute for our component function. Let's set a position attribute for each of our component instances. In React, you can pass on a property the same way as you would set an attribute for an HTML tag. We can write position equals and we pass on "0". We are going to use zero-based index here, because later on, when we specify some proper value for the squares, we're going to use zero-based index as well. We can also pass on a value in a bit different way. Instead of using double quotes here, we can also use curly brackets. Using curly brackets here, is called binding. It's a much more powerful way to pass some properties for child components. With curly brackets, we are basically opening a Window for JavaScript. Initially, we are in JavaScript land, but then with JSX we are starting to write some HTML. But what if you want to switch back to JavaScript inside HTML? Then we use binding, with curly brackets we are opening a Window to JavaScript, and whatever is inside these curly brackets gets evaluated as a JavaScript expression and the result of that will be passed on as a property. Right now we are not using its full power because we are just passing on a number. But we could also just use some mathematical calculation here, we could call a function here, have a ternary expression ... Anything that's a valid JavaScript expression, we can use here. There's also one minor difference here between passing on a value between curly brackets and passing on a value in between double-quotes. If you pass on a number between double quotes, it will be a text, it will be interpreted as a string. On the other hand, if you're passing on a number between curly brackets, it's going to stay a number. Let's go to the other side of things and let's use this passed on property in the Square component. As I said, properties in React components gets passed on as an attribute for the component function. But instead of the first attribute of this function simply becoming position, the first attribute we'll be a generic object for all the properties of the component. This can be confusing for components that have only one property. Be aware that the first attribute is still going to be an object, which has one attribute right now, the position. Here we can catch the whole props object and refer to the position attribute of props object, or we can decomposition this props object right away in the function signature. We have this position attribute now, passed on. How do we use it? Basically what we want to achieve is instead of showing "Square", we want to show the position number inside this component. What can we do in this case? We want to use a JavaScript variable inside JSX. We can do the same thing again, what we just did before with passing on a variable as a property. We can use binding. Again, we are using curly brackets and inside curly brackets we just use the position variable. After we did all this, we should see a unique ID inside each square, inside our grid.
6. The Changing Parts: In our previous lesson, we managed to pass on a unique ID for each square but inside the squares we rather want to have circles on crosses based on the progress of the game. This is something that's going to be dynamic. Initially, each square is going to be empty and once you click them they should show a circle or a cross. In React everything that's dynamic, everything that's changing over time should be defined in a state. The state together with the props are the two main factors that shape a component, but while the props are being passed on by the parents so they coming outside from the component, the state is an internal thing. What is changing here? There are two main things that are changing over the course of the game. In each turn, a square gets a new value. It gets a circle or a cross. The state of the squares is definitely something that we need to keep track of. The other thing that's changing over the game is the player. After each turn is changing from circle to cross or from cross to circle. These are going to be the two main parts of our state. Now we should discuss where to define the state. Regarding the player, it makes sense to define it on the top level because it has nothing to do with squares or circles or crosses. It's the state of the whole game. But regarding the state of the squares, it might sound logical to define them at the squares. Each square would be responsible for their own internal state. They would know if they should be empty or if they should contain a cross or a circle. But there's a major architectural issue with this one. The squares will know their own internal state but no one would know the whole state of the whole grid. That's because of how the communication works in between components in React. React works top to bottom. A top-level component, like TicTacToe component, can pass on properties to the child level components like the Square component but it doesn't work the other way around. The Square component, children cannot pass on properties to their parents. From the child perspective, the Square component can have access to the state of the TicTacToe component because the TicTacToe component can pass it on as a property but it's not working the other way around. The TicTacToe component cannot have access to the Square component's state because the Square component just cannot pass it on. We are going to see there's a workaround here. We can use callbacks to report back certain progress from the child to the parent but that's a bit different. With props, you're passing on a property. You're kind of exposing some of your variables to your children. But with callbacks, they're function calls. They're rather like an event. It's not like sharing your variables. Once we figured out how the communication works between components and how the state and props work together, we can probably agree that if you need certain logic, which is detecting if the game has finished and tells you which player won the game, then we need to have the state of each square in one common place. This is going to be one level higher in the TicTacToe component. Now we agree that we are going to have all our state in the top-level component and this is a quite common pattern. Usually, the top-level components are the smart ones. They usually have the logic and the state but they are not so visual while on the other hand the lower-level components usually receive all their values true props and they are the ones who are having to visual representations of the application but the state in general doesn't always have to be in the top level. It has to be in fact as low as possible but still as high as needed. Let's have another example for this. Lets say you're really good in game development and you created a website full of games. It will contain a TicTacToe application, it will contain a Tetris or Mine Sweeper etc. In this case, if you are having the top-level component, which is the whole page, it doesn't has to know the internal state of the TicTacToe game. We can still have lower-level states individually for each game and in the top-level, maybe there's no state at all.
7. First Attempt to Add a State: In the previous lesson, we had a lot of theory regarding how the state works and how the application components can be connected with props. Let's start defining our state. As we agreed. Let's move to the Tic Tac Toe component and let's define a state for the player and for the positions. The positions for now, it's going to be an array which will contain the value of each square in the grid. But before we define the states, let's just have some constants for the possible values of the squares. Let's define the states. For now, let's define the states as simple variables. Later on, we're going to see that the states have to be something special, something else than a simple variable. But for now, let's just keep it simple. Once we define the position state which is containing two value of each square, let just pass on this value for each square. We simply do it in the same way as we are passing on a position attributes for the component. We are adding a new prop here. Let's just call it value, which can contain empty circle or cross. Just to make this example a little bit more interesting, instead of having an empty grid as an initial state, let's just have some random crosses and circles in this state. Okay, so now we are passing on a value for each square, but of course, we also have to change the Square component to reflect these values. The Square component should contain a circle or a cross component depending on this value. To achieve this, we are going to use a JavaScript expression. This might be a bit confusing at first, but this is simply a Boolean operation. If the first part before the && is false, then the second part of this expression is not evaluated. Simply false is returned. But if the first part is true, then the second part will be the result of this expression. In this case that would be circle or cross. Luckily for us, if an expression is false, then react with simply ignore it. In this setup, only a circle or a cross should show up. Never both and if the value is initial, then this square should remain empty. Now in our grid, we should already see some circles and crosses depending on our initial state or at least the placeholder text for it. But before we change the placeholder text into actual circles and crosses, let's just stop for a second here, and let's think through how will this application work.
8. A State That Can Change: Before we move on, let's stop a bit and let's see how this application is going to work. So far, we have our function which is generating our initial state. After the initial rendering, the state of the game will change based on our interaction. Of course, we want to reflect these changes in the layout. The way React is dealing with this is by re-rendering the whole component and it will re-render the whole component by running the same function. This is a funny situation here, because we are running the same function twice and we are expecting a different result. I like to highlight here that this is just a normal JavaScript function apart from returning something that looks like HTML, there's nothing magical here. If you just look at this function, it's quite clear that if you are having the state in this format, this function is going to generate the same result no matter how many times do we run it. What can we do to fix that? We need a state that can give back the last value we assign to it. Therefore, we need to store it outside of this component. In React in order to solve this problem they introduced React Hooks. One of the Hooks is called useState and it's exactly for this problem. We the useState hook, we can store a state outside of the component and it will always give us back the latest value. The first time we are running this function, we can initialize the state with a value that we are passing on as an attribute. This attribute will be of course ignored in all the upcoming calls once the value is already stored. The useState hook returns an array of two items. The first item is the state itself. If you just run the function for the first time, then it basically returns our initial state. But if you are running the function due to a re-rendering, then it will return the latest value of the state. The second item that the useState hook is given back to us is a function and this function can be used to change the state. In the future for any interaction, if you need to change the state, we need to call this function and we not only call this function to change the state, but it's also automatically triggering the re-rendering of the component. So by changing the state, we also re-render the component, which of course we reflect the state change where we just had.
9. Circles and Crosses: This lesson is going to be fun, and it's an Easter egg because it doesn't have to do anything at all which react. In this one, we're going to code images. We're going to draw vector-based circles and crosses. If you ever check the source code of an image, then you probably realize that they are super complicated and you just can't get anything out of it. But we are going to use SVGs, and SVGs are not that complicated, especially if you are just going to use it for something simple. The nice thing about SVGs is that they are XML based, and since HTML5, they are part of the HTML syntax. You can simply inline an SVG inside HTML. You don't have to use an external image and you don't have to load it to the HTML. You can simply write it as part of your HTML. How do they look like? First of all, each SVG is wrapped around in an SVG tag. In the SVG tag, you can define the width and the height of the SVG along with the viewBox. The viewBox is defining your coordinate system. In our case, we are going to define that the SVG starts on the top left corner with the -50 -50 coordinate, and the width and the height of the SVG Canvas will be 100 each. So the center of the image will be zero, zero. You might notice that the height and the width that we defined in SVG and the height and the width we defined in the viewBox are the same but this is not something that's mandatory. The height and the width defined as attributes in the SVG tag are going to be the actual size of the SVG. While the viewBox is defining the canvas on which we can draw on. Every coordinate inside this SVG will relate to this canvas. The viewBox is defining an internal size from the perspective of the image items. If the actual size of the image and the size defined by the viewBox do not match, then the image will be simply scaled down or scaled up. Now we have a canvas. Let just draw something on it. Let's start with a Circle component because that's just a circle. We can simply add a circle tag and say that the center of it will be in the center of the canvas and the radius will be 40 pixels. You will notice that this will render a black circle. That's not exactly what we want but since SVGs are part of HTML, we can also use CSS to style it. Before the style, let's just define the Cross component as well. We simply define two lines by setting their starting coordinates and their end coordinates. Now if you're wondering, what did you do wrong because you're crosses not showing up, that's completely normal. By default, the line-width is zero. We have to change that in CSS. Let's define some styling for SVGs in general. Here we can set a line-width, which is called stroke-width. We can also change the color by setting the stroke property. Let's also remove the filling, which is automatically black in case of the circle. Let just say fill: none. If you want to be fancy, we can also change the stroke-linecap property, which will make our line endings rounded. If you want to have different colors for the circles and the crosses, then since we are in HTML now, you can simply attach a CSS class for the cross or the circle, then set a different color for them based on the CSS class. Now we have these good-looking circles and crosses. To finish off this game, let's move on with one of the most essential part, which is interaction.
10. Interaction: Okay, looking good, but so far everything is still static and this is a game so you want to add some interaction, so we should attach an event handler for the squares. But unfortunately in React, we cannot attach event handlers on component levels. We have to attach event handlers for the actual HTML tags. In our case, the closest we can get is the container tag inside a Square component. But there's a bit of a problem here, we agreed that we are going to have the state inside a TicTacToe component, but this event handler now is in the Square component. We have to find a nice way that the Square component, can set the state. One idea could be that along with passing on the state to the Square component, we could also pass on the setState function, and this way, the Square component could change the state itself. But along with changing the state of the grid, we also want to change the state of the player. Of course, we could also pass on to the player to the Square component and the Square component could change the whole state because it will know everything. But this is against the idea of having the Square component as simple as possible, and if you think about it, the player has nothing to do with the Square component really. The player belongs to the main logic which should be defined in the TicTacToe component. Instead of passing on everything, what we are going to do is we are passing on a callback. A callback is when you're passing on a function, then you are expecting that the function gets called on certain events. In our case, the TicTacToe component will pass on a function and the Square component we will call this function once it was clicked. The nice thing about this is that the function we are passing on is defined in the TicTacToe component, so it has full access to everything inside the TicTacToe component along with the state, and the player and while a Square component has access to none of these, it can still call the function. In the TicTacToe component, let's write a function that receives which square has been clicked, and it changes the state by updating the grid and changing the player. Then let's pass on this function to each of the squares, as a property. It's important to note here that we are not calling the function here. We are just passing on a reference to the function, just like we could do with any other variable. The only place where we are going to call this function will be inside the Square component, which is going to have access to it because we just pass it on as a property. Inside the Square component, we can define an event handler for the click event, and this event handler requires a function. It will be tempting to use the function which was just passed on from the TicTacToe component, but it's not that easy. The function passed on by the TicTacToe component requires a position attribute. What we can do is we can define an intermediate event handler in the Square component, which gets called once the square gets clicked, then it will transfer to call to our callback. In this intermediate click handler, we can easily pass on the position attribute because the Square component knows the position. We can also add some extra logic here, for instance, if the square is not empty, then we're going to ignore the click. Wow, so we gone far, I mean, now you can actually play this game. It's interactive, it looks nice. Everything's in place except one final bit, announcing the winner.
11. Detecting the Winner: We are really close to finish this game now, but we still don't know if the game has ended, if someone won the game or it's a tie. In order to do this, let's write a utility function, which is going to be a plain JavaScript function, and then let's see how this plain JavaScript function is fitting into your application logic. In order to do this calculation, this function would need the state of the game, it would need each square's value. But apart from that, it would be a plain JavaScript function, it's nothing React specific, it just a function that receives an array of nine values and it gives back a result. So detecting if someone won the game is checking if there's three circles or three crosses in a row, in a column, or in a diagonal way. Basically, we have to check the specific items in this array of nine items. If you want to check if the first row is full of circles, then we are going to check if the first, second, and third item in this array is a circle. If I'm going to this the second line, the second row, then we are going to check if the fourth, fifth, and sixth item in this array is a circle and so on. It's a super-simple check. It's basically some if conditions, if these values are all circles, then the function returns that the winner is circle. If these values are all crosses, then it will return that winner is a cross. If the function checked that no one won the game, then there are still two options. The game has either ended and it's a tie, or the game is still going on. Detecting a tie at this point is simply checking if all the squares have already a value, so there's no possible further move. In this case, let's return that "It is a tie". The only remaining option is no-one won the game, it's not a tie so the game is still going on. In this case, we simply don't return anything at all. OK, so we have this function and this is a utility function, so probably we can just have it somewhere outside of the React components, but we can also have it in the TicTacToe component because TicTacToe component is handling the main logic and it's the only place where this function is needed, so you can decide that. How does this fit into our application? The lifecycle of this Tic-Tac-Toe applications so far is that we are rendering the whole thing as an initial state, then once you're clicking one of the squares, then the whole thing gets re-rendered. This goes on in a loop till you keep on clicking squares. Detecting the winner could come after each click, so it could be part of the event handler after clicking a square. In this case, we could have an extra state for the winner. We could store the winner in a state, then based on that, we could render a result screen. The other option comes by realizing that the winner is a derived state. It comes based on the already existing states, so we don't have to have a separate part of the state for storing something that we can already figure out from the rest of the state. But if we are not storing it in the state, then where do we have it? We need to know if someone won the game at rendering, because in that case, we are going to render the Result component. So we can simply add some extra logic in between getting the state from the React hook, which is containing the value of the squares and rendering the grid based on this state. Anything you write in this function, as we discussed, we'll be rerun with every render. When you are re-rendering this component, it will detect if someone won the game and then it can make a decision to render the results screen based on that. So these are two options and feel free to go with whichever you prefer. In the end, both will have a winner variable which will contain if the circle or the cross won the game, or if it's a tie or it won't contain anything and that will indicate that the game is still on.
12. And the Winner Is...: In this last chapter, we are going to create our results screen. Previously, we already managed to derive our state into a winner variable, which will contain, if the game has been won by the circle, the cross, or no one won the game and the game is still on. The results screen will come to the TicTacToe component because the TicTacToe component is the one who is assembling the main logic of the game. In the layout, the result would show up on top of the grid but technically in HTML, it's going to be next to it because the grid already has some distinct CSS, which is specific for the grid, and we don't want to have the results screen inside of that because the results screen would look something completely different. But now we have two HTML tags inside the TicTacToe components results. And in React, we cannot have that. React always have to return one HTML tag as a result. But we can easily fix this because that one result tag can have a content and that content can have multiple HTML tags. It just the same as our previous grid is containing nine squares. I'll just simply add a wrapper tag as a container for the Tic Tac Toe component, which would have both the grid and the results screen. But now both the results screen and the grid is showing up always and we only want to have the results screen in case someone won the game or if it's a tie. We want to render this results screen conditionally based on the winner attribute. We can do the same trick that we just did in the Square component when we rendered a circle or a cross based on the value of the square. Now based on the value of the winner, we're going to render the result. As we agreed, if the winner is empty, that means the game is still on. This would also mean that if you're using this condition, that if the game is still on, then the results screen won't show up. We managed to hide the results screen during the game. We also want to make it smart enough to know who won the game because right now it simply says result, it doesn't say what's the result. In order to do so, we need to pass on the winner attribute to this component just the same way as we passed on attributes to the squares. Then on the other side at the results component, we need to catch this variable and we can have some conditional rendering based on its value. By default, this would show up below the grid. But if you want to have it in top of the grid, then we can add some CSS style and with that, we can set it to position absolute and set some other properties to make it a bit nicer. Once you've finished the game, the winner has been announced, what's next? If you want to play another round, then you have to refresh the page. Instead of that, we can also define a reset function which would reset our state. Because we are resetting our state, we have to define this in the TicTacToe component because that's the one who's having access to the state. But after that, we can pass on this reset function to our results screen component. This is going to be yet another callback, just the same as we were passing on a callback to the Square component, which was used once you click the square. This one will be used if you click the reset button in the results screen. I'll just pass on this function as a property and inside the results screen component, if you define a button for resetting, then we can simply pass this function on to this button's onClick event handler, without any mid-level event handlers in between. The difference between this one and the one at the Square component is that the one at the Square component needed some extra property to be passed on to the TicTacToe components function. But this one, the reset functions doesn't need any property at all, so it can be simply called, it can be simply binded to the event handler of this button. And that's all it is. Now we have a game you can play it through, the result screen will show up and once you're finished, you can reset the game and play another round.
13. Conclusion: Congratulations. Now I have a Tic-Tac-Toe game, and hopefully you'll also have a much better understanding of how React works. But if you still have some questions or some parts are still confusing for you, then feel free to reach out to me here or on CodePen. Of course, this game is barely finished. We could have much more to it, but that would have made a much longer tutorial. Instead of that, you can find a link below this video which is explaining some further features like how to add animation to it, or how to define a computer logic and play against the computer. Feel free to move on with this project, and once you're finished don't forget to share it. I can't wait to see it.