Skip to content

Instantly share code, notes, and snippets.

@dogriffiths
Created October 2, 2023 11:07
Show Gist options
  • Save dogriffiths/f96379261919ea345f32ea69c4fa00af to your computer and use it in GitHub Desktop.
Save dogriffiths/f96379261919ea345f32ea69c4fa00af to your computer and use it in GitHub Desktop.
So today's talk is called From Local State to Global Control.
Now, I didn't come up with this name. This was actually, I think, might have been handy, but I think it's a really good talk and it's given me the structure for today.
So just to tell you a bit about myself, I'm an author. I've written probably about six or seven books, a lot of them with my wife.
Probably most relevant to today is a little while ago I produced a book called The React Cookbook, which is I'm going to be taking some examples and some code from that today.
I'm the founder in the UK of a company called HearScreen, which is all to do with kind of booking your time at work and is completely irrelevant, mostly to what we'll be talking about today.
And if you want to follow me on social media or have a look at any other code or books or things that I've written, if you go to this URL, linktree.do.griffiths,
I will say you'll be getting a copy, I believe, of all of the slides that you'll see today.
And at the end, I'll give you some useful links that will tell you how to get all of the code we look at and also more code that we'll cover today.
I was going to do a longer presentation, but when I tried it, it was going to take about four hours.
So this is the slightly shorter presentation.
But when you have a look at the repository later on, you'll find that there's actually a longer version that's got a lot more slides, a lot more detail about things.
So the first thing I thought I should probably say is something about why I wrote the book.
I mean, obviously fame and fame and wealth were the two main reasons.
But why else? What were the other reasons I wrote the book?
Well, until probably two or three years ago, I was working as a consultant, which meant I was going from company to company for just a few weeks at a time.
And I was working mostly on React projects.
It was what I did for most of my day job.
And what happens when I know that people have got a variety of backgrounds when you're actually a professional developer, you tend to you find it easier to get jobs and you can get paid more if you've got more experience.
And what experience really means is that you've got a bigger kind of bag of tricks.
You've got a bigger kind of set of examples of problem solving code that you can take with you from job to job.
And the more jobs that you have, the more of these examples that you start to gather.
And it's almost like collecting a series of magic spells.
Now, I've been a consultant for a very long time and I collected quite a large set of these kind of magic spells where you could get a particular technical problem.
And I'd found previous ways of solving that technical problem.
And so what React cookbook actually is, is a collection of problems and solutions.
I think there are something like 87 different recipes they're called and they're called recipes because it kind of, you know, you are not supposed to just use them exactly as is.
It's like a real recipe book where you might vary the ingredients.
And so in that sense, it's a book for kind of professional developers, but also people who are new to being professional developers or for people who are new to the React framework itself.
So what I'm going to go through today is I'm going to go through a few of those examples, but I'm going to use Hamdi's title to provide some kind of structure today.
So I'm not just reading bits of code to you.
So I'm going to talk about state.
Now, state is about remembering things.
Now, I would say that in React, I'm going to talk about there being about four different levels of states.
Now, different people looking at React would probably break this down in different ways, but I like to think of it as having kind of four different levels of state.
And so today I'm going to go through sort of four sections of today's talk and showing you how state is used in various levels of a React application.
Now, the first level, I'm going to call component state.
So as I'm sure you're aware, React is made of these separate little components.
In fact, let me do some drawing.
Let's see if you can see my desktop.
Can you see me?
Have I down in the corner?
Hello.
Let me just go and delete this.
So in React, React is built up from components.
And whenever you've got any kind of component based architecture behind the scenes, everything is living in this sort of tree of components.
Now, in React, there are two ways, two fundamental ways of creating these components.
You can either use classes, you can create a component class, or more commonly these days, you go and create a little function, a small JavaScript function.
And the JavaScript function will look a bit like this.
You know, you might have some piece of state, probably using the use state hook.
And in this case, we've got a piece of state called name and it's got a default value of string.
And we get these two things, but we get name, which is just a string value.
And we get set name, which is a function which we can call that function to change the value of name.
And so we can display name and then we can also we can change the name.
So this is a very simple component where you can type a name into a text field.
And the magic of React is, as you guessed from the name, it's reactive.
So when this line of code in the input field, when I go and call set name, not only will it change the name of the variable,
but it will also redraw that bit of HTML on the screen.
This is a little magical.
If you've ever worked with JavaScript that's not reactive, then this is quite a good feature.
Now, whenever you're doing, whenever you're creating components, it's always good if you can make them simple.
You're going to make a very simple component because a really good simple component is one that you can look at on the screen.
This is a good sort of idea for you, a little metric.
A good React component is one that you don't really have to scroll very much on the screen when you're writing it or editing it.
And so this means that people tend to, rather than create one great big component, they break that component down into lots of small components.
And that's fine most of the time.
And React is very straightforward.
It's very easy to use.
But occasionally you'll find that you'll get components that have got quite complex internal bits of logic.
Now, this is an example, actually.
And I can show you this example on the screen because I've got a server running, I think.
So let me show you here.
So this is like a small number puzzle and all of the code for this, I say, you'll be able to download later on.
So this is a small number puzzle.
I'm sure you've seen these before and you can move things around on the screen.
And so this component has to track the position of all of the tiles and it has to track also where the empty tile is.
It has to have all of the logic.
So if I go and click on eight, it knows to move eight sideways because that's where the blank square is.
And it knows if I click on three, three can't move.
So it can't move that one.
It's also got a shuffle button that will move things around randomly.
And it's got a reset button that will reset all of the tiles into the right position.
And notice at the same time, it also has the ability to work out when this puzzle is complete, when everything's back into the right position.
Now, it would be very difficult when you've got a component like this to break it down into smaller components that are simpler,
because you've got lots of component state in there that's talking to each other.
And so occasionally what you'll find is that rather than have a very small piece of code that's got a little bit of state in it,
and then it's got some UI code at the end that says this is what the HTML looks like.
Instead, what you can get is you get components that scroll on for page after page after page.
And you'll have a little bit of HTML at the end.
And then you'll have a huge amount of very complicated code at the top.
Now, this is a problem.
This is a problem if you're going to maintain the code because it's really difficult to see what it does.
And it's also very difficult if you want to test the code because it can be it can be quite tricky to test UI code anyway.
And it can be very difficult when you're testing UI code to work out whether you're covering all of the code in there.
And so one of the things that you can do is to try and separate out this complex code and split it and put it somewhere else in a different file.
And separate it out from the component itself.
Now, this is kind of a thing that other frameworks like Angular have done for years.
And React people always said, oh, no, you should always have all of your code together.
Keep it all nice and simple.
But it can be useful if you've got a very complex component.
I wouldn't do this all the time.
But if you've got a very complex component, it can be nice to take the complicated logic and move it into a separate file.
And I've got a recipe for this one 3.1 in the book about managing complex component state.
And the trick that we actually use is if you've got, you know, a lot of new state calls and you've got complex code that's interacting between things, we create this thing called the reducer.
Now, what's a reducer?
A reducer is actually just a straightforward, simple piece of JavaScript code.
It doesn't normally need any special imports.
It's just a function.
It's just a JavaScript function.
And it takes two things.
The first thing is some sort of JavaScript object.
Might be an array, might be a simple JavaScript object.
And it's got data in it.
You don't normally put any code inside your state object.
And it also has this second parameter called the action.
And what happens is a reducer is what's called a state machine.
So you say, here's a lot of values in this state object.
And here's a command for how I want you to modify those values.
And what the reducer function will do is it will return a brand new state object that's been modified according to the action.
So, for example, what you would normally do, your action, you will often give it like a type attribute.
And you would then say, well, if the type of the action in this case is to shuffle all of the tiles on the screen,
I'll go and put in all of my very complicated code, which in this case will go through and randomly move tiles around on the screen.
It'll do about 300 random moves and then return a new copy of the state object.
Now, this means that this is pure JavaScript.
It's completely separate from the from the main code.
And if I go and show you.
So for this particular puzzle, I'll just go and show you what the component looks like.
So for the. Let's see if I can move it up to my main screen.
So for my main puzzle component, you can see it's.
If I can go into demo mode, would this be a really bad idea?
I go into presentation mode just to make the text nice and big.
There we go. So you can see this is the entire UI code.
And you'll notice that although it's a little bit long, given the amount of complexity in this user interface with the ability to do all of these things,
there's very little actual complex code in there.
All it really is is just a big pile of HTML.
And the reason it was able to work is because we've got this reducer function to create.
It's just this simple JavaScript function.
And then there's a hook called use reducer.
And you give it an initial state and it gives you two things back.
It gives you the current state, you know, where your tiles are, those kinds of things, and it gives you a function called dispatch.
Then you use the dispatch function to go and do something.
So if I've got a button that, for example, is resetting the puzzle, I just go and say call dispatch with that action object.
So that's the command, if you like, and magic will happen behind the scenes.
It will then go and call the reducer function for me.
And the great thing about the reducer function is it will then work out if the state has changed as a result of my action.
And if it has, it will then redraw the puzzle.
So it makes this state object reactive.
Now, this probably seems like it's quite a complex thing.
We could have put all of this code into this file and, you know, well, we could probably live with a big piece of code.
But there are several advantages to using a reducer.
Let me just go back to my slides.
Now, one of the advantages, as the code to actually use it, one of the advantages is that you can actually test reducers.
So you've got all this very complicated code that's moving tiles around on the screen.
And if I try to create an automated test for a browser, that's quite complex.
But given that all of the complicated, thinky stuff, all of the complicated code that might go wrong is now living inside a reducer function.
And that reducer function is just a JavaScript function.
It doesn't know anything about web browsers.
I can test it in a very simple way.
So I can go and create, I don't know if you've done any automated testing, but I can go and create a little file called reducer.test.js.
And I can create these different test scenarios.
So I can say, well, let's imagine that you're starting off with tiles in a certain set of positions and it will be an incomplete set.
It's actually one tile away from completion.
I can then say, go and move the final tile into place, assert that the puzzle now looks like it's complete.
And then I can move a different tile around, although I can assert that the puzzle is no longer complete.
And then you can go write lots of these different tests.
And so when you've got very complex code, you can test it more easily.
Much easier to test it, makes it much more stable.
So this is very good if you've got a component that's one component that got very complicated, gnarly logic inside it.
You can test it and make it much more stable.
But there are some other advantages.
The other thing that you can do now to this, I'm going to actually have to go in the background, start to stop some servers and start some other servers.
The other things that you can do is that because reducers have a kind of standard, they have a standard structure,
you can write general pieces of code that modify their behavior.
Now, this is an example of I'm running a slightly different version.
Now, what happens is whenever you call a reducer, you say, here's a state object, set of state.
Here's a command to modify it.
The reducer gives you back a modified version of the state.
There's an example in the book where what you can do, because that's a standard structure for the reducer, you can wrap it in another thing that will make it undoable.
So what you can do is you can create an undo function.
That's a general undo function that will work with pretty much any reducer.
So if I go and make some moves, this is more or less the same code.
But now you'll notice at the bottom of the screen, I've now got a couple of buttons called undo and redo.
And what I can do is I can undo all those changes.
Now, this would be incredibly difficult to do.
It works with everything.
If I go and shuffle things a couple of times, I can undo those shuffles.
Take me back to how old it was.
This would be incredibly difficult to do if all of that code was still inside the component.
So how does this undo thing, what's it like to actually use?
I'll show you in the cookbook how it works.
This is a piece of code that's this is lines of code from the puzzle that's using a reducer.
Reporting use reducer and then be calling the use reducer.
What you can create is another custom hook.
You know, this use reducer is a hook.
You can create your own hook called use undo reducer.
And then you use that rather than just use reducer.
So if you're using an undoable version of the reducer, you don't have to change the reducer function at all.
And you can just put on the undo button that just sends the command to undo.
So I'm waffling a little, but yes.
And now we move on to that one.
So the only questions about that one.
So that's component state.
Now, component state got to be a bit careful with reducers.
I would only use them in cases where you've got a very complex component.
You know, you can see people that immediately they like reducers.
Now, every time they create a react component, they go and create a reducer for it.
You've got to remember that when you're using reducers, you're adding a little bit of overhead.
They can be slightly confusing when the first time you use them.
But certainly if you're doing complex components, they're a really good idea.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment