State Management in React with Chance Strickland

Joel Hooks
InstructorJoel Hooks
Share this video with your friends

Social Share Links

Send Tweet
Published 4 years ago
Updated 2 years ago

Joel and Chance chat about the big ideas of State Management and when you should start implementing a State Machine in your application. Chance gives a walkthrough of how Reach UI handles State, how the Listbox component was built, and how reading the React UI source code is an excellent source of learning material.

Resources:

Reach UI

What are the big ideas of State Management?

  • A good starting point is understanding why React is so popular. React gave us a very convenient way of thinking about our application based on State. It determined that you're UI is a function of your State.
    • That was a simple and revolutionary idea that changed how we manage the State.
    • Tools like Redux and Flux have helped us think about State at a higher level.
  • State should be managed closer to the components. The closer you can keep the State to where things are happing, the more deterministic.
  • Reach UI - uses a State Machine model.

When should you add a State Machine?

  • It's essential to understand what a State Machine is first. A finite-state machine is a mathematical model of computation. You will only have one State at any given time.
  • First, you would define your States and then integrate events.
  • You always want to think like a finite-state machine when building a new component.
    • Once you start thinking in those terms, you start writing your code differently. An example of this is Boolean props (having a button with three different color props).

Is our application a State Machine?

  • Yes. For example, you can turn a reducer pattern into a State Machine by adding a second reducer.
  • State Machines do a great job connecting how designers and developers work/think.
  • Designers are always thinking of State.
    • If you get a component mockup, you'll get a design with all the different State.
    • They are writing a State Machine in a visual format.

What was your favorite Component in Reach UI that was a challenge building?

  • The Listbox component was the most challenging; a Listbox presents a list of selectable options in a popover, which is toggled on or off by a button.
  • Visually and behaviorally, it is similar to @reach/menu-button except that ListboxOption components hold a value.
  • In this sense, they are more directly comparable to HTML select elements.

Listbox

  • (A bad example of this is Ant Design)https://ant.design/components/select/
    • When you open, you can't select on mouseDown. Unlike with the native select - Web/HTML/Element/select
    • People don't use native features due to ascetics preferences and the ability to add functionality.
  • Notes: you should always try to use the native elements.

React UI and XState

  • Reading the Reach UI source code is an excellent source of learning material.
  • Reach UI contains @xstate/fsm, a miniature version of XState.
  • Before XState, Ryan wrote his own Transition:
// https://github.com/reach/reach-ui/blob/a376daec462ccb53d33f4471306dff35383a03a5/packages/tooltip/src/index.tsx

/**
 * Finds the next state from the current state + action. If the chart doesn't
 * describe that transition, it will throw.
 *
 * It also manages lifecycles of the machine, (enter/leave hooks on the state
 * chart)
 *
 * @param event
 * @param payload
 */
const transition: Transition = (event, payload) => {
  let stateDef = chart.states[state];
  let nextState = stateDef && stateDef.on && stateDef.on[event];

  // Really useful for debugging
  // console.log({ event, state, nextState, contextId: context.id });
  // !nextState && console.log('no transition taken')

  if (!nextState) {
    return;
  }

  if (stateDef && stateDef.leave) {
    stateDef.leave();
  }

  if (payload) {
    context = payload;
  }

  let nextDef = chart.states[nextState];
  if (nextDef && nextDef.enter) {
    nextDef.enter();
  }

  state = nextState;
  notify();
};
  • This component also contained a StateChart, which takes the main ideas of a State Machine to handle several events.
// https://github.com/reach/reach-ui/blob/a376daec462ccb53d33f4471306dff35383a03a5/packages/tooltip/src/index.tsx

const chart: StateChart = {
  initial: IDLE,
  states: {
    [IDLE]: {
      enter: clearContextId,
      on: {
        [MOUSE_ENTER]: FOCUSED,
        [FOCUS]: VISIBLE,
      },
    },
    [FOCUSED]: {
      enter: startRestTimer,
      leave: clearRestTimer,
      on: {
        [MOUSE_MOVE]: FOCUSED,
        [MOUSE_LEAVE]: IDLE,
        [MOUSE_DOWN]: DISMISSED,
        [BLUR]: IDLE,
        [REST]: VISIBLE,
      },
    },
    
	
...
  • At the end of the day, Reach UI has a great user experience because it's designed from a component standpoint.

Research of Git History

  • Chance went back through the Reach UI git history to analyze and understand in-depth how each component has evolved over time. Then he re-engineered a new component following the Reach UI style.

Interviewer: [0:01] I've been doing this thing where I talk to users, which is interesting. You start asking people what their deal is in React state management. Oftentimes, in many different guys', I think it comes up as the perennial problem with developing applications in general, how do you manage state.

[0:27] I've been asking people that have experience how they go about it. I thought it would be cool because one of the examples I like to send people when we're talking about component state is Reach UI.

[0:40] I think that as a library, it's done that really well. It's the base layer of the rest of the application. It's how you even start to consider state in your application, and like you should start it, component state. That's the kind of things. I have a few questions that I laid out, lead with if you want to answer them.

Chance Strickland: [1:02] Sure, go for it.

Interviewer: [1:04] Think about state management and how you consider it in your experience. What are the big ideas or essential questions that people should be considering about the activity or the end result of state management?

Chance: [1:22] Thinking about the big ideas, I like to start at why tools like React are popular in the first place. I think React is popular, mostly, because it gave us a new, I wouldn't say new, but it gave us a very convenient way to think about our application in terms of its state rather than a lot of older paradigms.

[1:46] Specifically in the Web, where we had to write this very imperative code, where we went and told our application what to do and what to change based on certain things that happen over time. Then React came in and said that your UI is a function of your state.

[2:01] Now, all we need to know is what the state of your component is and we can do the rest as far as determining what your UI is going to look like. That was simple, but also revolutionary in a lot of ways, at least for where we were on the Web. I think that set the stage for how we think about state now and how that's evolved over time and...

Interviewer: [2:27] React itself is a state management library in the center...

Chance: [2:30] From day one. Yeah, it's always been at its heart about managing state. It's just evolved over time and in terms of its tactics for doing some of the tools that we have now or are a lot better for managing state internally.

[2:47] I think those ideas were always based on Reacts fundamental offering, which was you can write your UI very expressively, very declaratively based on your current state. That's just a much simpler way to write a component. It caught on and that's how we've been doing it ever since. You have tools, things like Redux, and Flux that came along.

[3:14] Some of the pinpoints that spurred our thinking on state, I think, as your state gets more intertwined and more complicated, having these single data points, this single state keys that act on their own, having one state, you can set your state, but you're only really setting one state item at a time, and it's based on a mouse down event or something.

[3:41] As things get more complicated, different pieces of your state and your application start getting interdependent on one another. Things like Redux and Flux patterns helped us think about these things more holistically, I think. That's why they were popular.

[3:58] Then React got smart and learned from some of the patterns that were adapted early on in third party libraries and they developed the context API, which gave us an internal mechanism for dealing with state at a higher level.

[4:14] It never really changed the fundamental aspect that you can manage state at the [inaudible] level. A lot of people think of context state as global, which is never really been the case. It's really not even the best use for context, in my opinion.

[4:33] State is typically better managed as closely to the components as possible, the leaf nodes as possible. The closer you can keep that state to where things are happening, the more deterministic things are, and the more componentized things are.

[4:51] That doesn't necessarily mean you get them into component, you can keep them a couple levels up in the tree, but it doesn't mean you have to go and throw it on global state. You don't necessarily have to have this giant global store where you keep everything. I think that's really cool.

[5:05] It's great that React provides us a really good tools internally without having to reach for third party libraries, but there are other ways of thinking about state. In terms of Reach UI, we've adopted a state machine model for newer components, and we'll probably stick with that moving forward. I really enjoy state machines. I'm sure we'll talk about that a little bit.

Interviewer: [5:32] They're on my shortlist, for sure. I think it's interesting because you talk about context, and I think people usually think of it as the whole of the application state, where to me, an application is a graph of components, but inside of that, you have...I view any React component potentially as an application depending on how it grows into the thing.

[5:58] You can have a graph of components that all need to share a state, but that doesn't necessarily mean it's global. It just means that you're talking about a slice of your applications. Is that fair?

Chance: [6:10] Yeah, and that's exactly how we think of it in Reach UI. I think it's even more necessary to think that way when you are writing a library that is intended to be consumed by whatever application. We have no context of your global application. We have to manage our own state internally based on what we know the component needs to do.

[6:29] That's basically it. We can give you the keys. If you need to do something externally to go in and model your usage based on external state, that's fine. We can control the state of these components. React also provides this nice paradigm of thinking of state as either controlled or uncontrolled.

[6:49] Thinking of form elements is a good example, where we have an input, and you can either let the dom maintain control of that input state or you can say, "Nope. I want React to control that input state, and I want to specifically control it in my component and always have a source of truth internally."

[7:06] We model all of our components in Reach UI off that same way of thinking about these individual units as either controlled or uncontrolled, basically meaning are we controlling it in the library or are we basically saying, "You can control it and just give us the values and we'll still behave deterministically based on the values that you give us, but the control is now yours, and you can manipulate it wherever you want?"

Interviewer: [7:33] We'll help you out, but if you know what you're doing, then you can completely manage it yourself. At that point, Reach stops being part of your state management and you're having to take control of that as a developer. Is that...

Chance: [7:47] Yeah, to a degree. It's really more about, if you were to need some internal state from, let's say, a combo box -- if you need to know what the state of that input is at a given time -- you just control it higher up in the tree, and you pass those values down into the combo box.

[8:04] Now you have this one combo box value that you're able to control anywhere in your application. Then you can take it as high up in the tree as you need it. We can't always determine where that state's going to be needed, so we can give you the ability to do that.

Interviewer: [8:18] I know from my frequent warnings that that's usually a loop. There's an event associated with the property, and when you're dealing with a controlled and uncontrolled components, you're almost always in parity with the event, the update, and then the value, right?

Chance: [8:35] Yeah, exactly. There may be other types of events that can also update those values. That's where I think thinking in the state machine paradigm becomes really helpful because when you're defining state machines, you are defining your state based on whatever your prior state was -- or whatever your current state is, rather -- as well as the event that's coming in.

[8:56] It might be a keystroke event. It might be a selection event in the case of a combo box. It might be something from somewhere else completely. It might be some data comes in from your current location in your router, and it updates an input for you.

[9:14] We don't always know those events. That's why it's really important to give people the ability to control that to a certain degree.

Interviewer: [9:20] What sort of power does a state machine bring to the equation? When do you start thinking, "Oh, I really need a state machine"?

Chance: [9:35] First of all, it might be helpful to describe what state machines are, what they're for.

Interviewer: [9:40] Good idea. [laughs]

Chance: [9:43] Really, you'd call it a finite state machine, to be more explicit. The idea is that you have a finite number of states that your application or your component can be in at any given time. That's it.

[9:59] If you have a checkbox, it's either checked or it's not checked. Those are your states. Maybe you have a mixed checkbox as well -- there's an indeterminate state. Let's say there's three states to your checkbox.

[10:10] That's it. There's nothing else. Whether or not you can move from one state to another is not only determined by your current state but it's determined by your current state and an event that might be triggered from somewhere. You can't always move from one state to another state unless you explicitly declare that in your state machine.

[10:35] A practical real-world example is a red light, a stop light. You are never going to move from green directly to red. That is an impossible state. You should never be able to make that transition. It's an impossible transition.

[10:52] You should never be able to do that. That would cause chaos. Accidents would happen everywhere because people would be slamming on the brakes and running through intersections. It would be terrible. You always want to make sure that you go to that yellow state.

[11:04] In your state machine, you would define your number of states, like what are the actual states we can be in? We can be in green, yellow, red, or maybe dysfunctional -- maybe the power went out, and now we're at blinking red.

[11:20] You would define your state machine. First you would set up your states, and then within each of those states, you would define in which situations you would advance to another state.

[11:30] If I were at a green light, I might have a timer that says after a minute and a half, the green light transitions to yellow. It does that when we get an event from somewhere. Maybe it's the caution event, or something.

[11:50] In our application code, all we have to do is send an event. We would set a timer. We would say "Set time out, call back, send this event to the machine." The machine gets it. Based on the current state that you're in at that time -- in our case, we're in green -- now we know, because our state machine tells us, that the next logical step is yellow.

[12:11] If we're in red and we get that same event coming from our app, unless we tell our state machine to do something with that event, there's nothing to do, and so no transition actually occurs.

[12:24] We just stay in the current state. It just ignores it, basically, which turns out to be a really nice way to model your state because it helps you think deterministically about what states you're allowed to be in when certain events happen. It makes it a lot easier to debug things when they go wrong, in my opinion, especially with your more complex UI components.

[12:47] I think your original question was, when do you decide to use a state machine? That was sort of a long-winded getting to that, but I wanted to make sure that we were able to set the stage for what they actually do and what purpose they serve.

[13:00] In the definition, at its very core level, I think you always want to think like a state machine, in the sense that you want to think of the actual finite number of states that your app or your component can be in at a given time.

[13:16] I think you should do that with every component, always, from the very beginning. It should be a fundamental part of your component design. Once you start thinking in those terms, you will immediately, I think, start writing things a lot differently than you may have otherwise done so.

[13:31] A really common example are Boolean props. In a React component, if you were to pass a bunch of Boolean flags through a button, say, like is our button disabled? Is it an expandable menu button or something? Is the menu expanded? It has all of these Boolean props that basically are responsible for one singular thing.

[13:52] If you think of your button in terms of its available states, like "What are the current states of this button?" you can start thinking of the prop design a little differently, your API designs a little bit differently.

[14:03] As these things become intertwined, let's say there's -- there's another good one, I think is, for a button specifically is if you have a design system and you have three different colors. A really old-school way of doing this is just to set a class name on your component and say class=button(green), class=button(red), button(yellow).

[14:24] Those are basically Boolean flags in the form of a class name. What happens if you have button(green) and button(yellow) at the same time? Unless you have some magical CSS function that melds green and yellow, that doesn't make any sense. Instead, you would have a color prop, and you would say what my color is.

[14:46] It's a very basic example, but just thinking in terms of the different states that your button could be in at a given time, now I know that colors can only exist one at a time.

[14:57] I might not use a color or I might not use a class name prop or something that is going to take a multitude of color values and then make some sort of determinations internally based on whatever that combination happens to be.

[15:14] That's very hard to debug at a certain point. That's at the very base level. Then as your application gets more and more complicated and as state starts getting really intertwined, I don't think there's a magic moment where you think, "I need a state machine," but you can start thinking about when you need maybe a reducer.

[15:38] My rule of thumb is if I have two state nodes that are dependent on one another, I immediately use a reducer. I stop using single state values and I start using a reducer because now these things are dependent on one another and I need setters that are going to logically set my state based on the value of one or the value of the other rather than treating them independently.

[16:00] I think it just makes things a lot simpler to think about and makes it really easy to continue to help that component grow over time and manage it as it grows, which they often do.

[16:14] You can actually turn a reducer into a state machine pretty simply without using any third-party libraries.

Interviewer: [16:20] That kind of leads to my next question, which is, is our application a state machine whether we are formally declaring it or not? We're just doing it ad hoc in kind of a who-knows-what's-going-to-happen sort of way?

[16:32] Every time we set a flag or we do this, we're adding to a state machine. We just can't really hold it in our head and think about it when you go to a formal state chart, finite state machine approach. Is that...?

Chance: [16:44] Yeah. I think so.

Interviewer: [16:49] To me, a reducer in the Redux sense, where you have a switch statement is a little state machine.

Chance: [16:54] Absolutely. It is, but the piece that I think the reducer pattern is missing is -- well, let me back up. When I say the reducer pattern, I mean the common pattern that most of us think of when we think of...

[17:09] [crosstalk]

Interviewer: [17:09] Switch statement, return a default, and expand the state object as it comes in, Redux-style. That's all...

Chance: [17:17] Redux-style, yeah. Usually what you do is you do is you get an action type, and your switch statement is all based around that action type.

[17:25] If you want to turn your reducer into a more deterministic finite state machine, all you really need is one more switch statement. Just above your action type switch statement, you would have your current state switch statement.

[17:36] Now you've got these two nested switch statements, but now you're basically saying, "Not only am I checking the action type that's coming in, I'm checking what my current state is before I do anything to know if that action type ever does anything."

[17:49] In a red-light example, if we were to pass a turn yellow or send a turn-yellow event into our state machine and we were just using the old-school reducer way of doing things, now we're technically able to go to yellow whenever that event comes in, no matter what.

[18:08] Whereas if we guard against the current state too, we now are only doing something when we explicitly tell it to do it based on the current state that you're in at that given time. There are other ways.

Interviewer: [18:19] That's the transition.

Chance: [18:19] Yes.

Interviewer: [18:19] What really separates it is this idea that we're able to one, see the current state and allow transition based on that definition, which like with that Redux reducer, we're not really caring, it all just flows through. Once it hits a match, then it's done and it misses that transition concept at all, for the most part.

[18:40] I know that you can do it. I've seen it to where you bail out early with a Boolean or an if. I don't know that I've ever seen anybody use a double-switch-statement approach, but that makes sense. It's the same thing. It's a conditional.

"[18:55] We can do this now, so proceed," and once you jump into a state machine that's all formalized and you're able to design with that in mind. To me, it really shines as a design tool. I like the practical, common idea of coding against a state machine. I love the design aspect of it and having to think through these problems before you even start typing code. It's one of the cool things to me.

Chance: [19:25] I agree. State machines do a really good job of connecting a very common disconnect between the way designers and developers think. Designers are always thinking in terms of state, so when you get a really good component mockup, you're often going to get that component mocked-up in your various states.

[19:45] If you get a button for your design system, the designer's usually going to think of, "Is the button hovered, is it focused, is it disabled? What are all these states?" They're giving you the states. They're essentially writing a state machine for you in visual format. You can take that and turn it into, very directly, a state machine that helps you manage those states very, very nicely.

Interviewer: [20:08] Do you have a favorite component in 32i that was a state challenge, maybe?

Chance: [20:14] Oh, yeah. It just happens to be the last one that I wrote. I like to think that every time I wrote a new component it got a little bit better, but it's also just because it was the hairiest and the most complicated. It's our list-box component, which is basically a custom select menu.

Interviewer: [20:30] Is that combo box? Is that an aka for that?

Chance: [20:35] Combo box is different. The two patterns are combo boxes in input form and you type something in and as you type you'll get a list of suggestions based on what you typed. A list box is just a simple drop-down with a value, just like a select.

Interviewer: [20:49] Got you. Can you show us?

Chance: [20:51] Yeah. Let's bring it up real quick. I've got the code pulled up here already. We can keep that in the background.

Interviewer: [21:00] You've got it in Action over here?

Chance: [21:05] Yeah. I'm spinning up our Storybook right now. It's a simplified version of that. Look at my first activity in GitHub, Digital Gardeners.

Interviewer: [21:17] It's nice.

Chance: [21:18] It's getting popular now.

Interviewer: [21:17] I was just looking at that. That one's going around in some tweets, actually.

Chance: [21:23] I saw that.

Interviewer: [21:25] It's like a book club company now.

Chance: [21:29] It's starting to seem that way.

Interviewer: [21:32] We do book clubs.

Chance: [21:33] There's a convergence between the Party Corgis and the Eggheads. They are one now. We should really speed up Storybook, shouldn't we? It's slow.

Interviewer: [21:46] Get faster computers, whatever.

Chance: [21:51] This our list box component. Essentially, like I said, you have a select menu where you have a button, you click the button and you get a list of options. Now, this is a very common pattern. You see a lot of custom select menus out in the wild. They're all over the place and they're notorious for being terrible. We tried really hard to make ours as not terrible as possible.

Interviewer: [22:14] What makes them terrible? I would like to know, "What are the top qualifications of a terrible list box?"

Chance: [22:20] Do you want me to pick on one in particular?

Interviewer: [22:21] Yeah, sure.

Chance: [22:22] I can pull one down and show you.

Interviewer: [22:23] Let's roast somebody.

Chance: [22:26] I'm going to roast Ant Design for a minute. I love to pick on them. The reason I love to pick on Ant Design is because it's very popular, everyone, not everyone, but a lot of people use it. It's very, very popular.

Interviewer: [22:37] It's funny you say that because I literally never heard of it. It's new to me, but I get the concept.

Chance: [22:44] It's a big component library. They have a ton of stuff. I get why it's popular. They're pretty to look at.

Interviewer: [22:49] Yeah, they do a lot of work for you.

Chance: [22:51] They do a lot of work for you. The problem is they don't work that well. Let me start, actually, by just looking up the MDN documentation for select and let's just look at how a native select behaves. It's going to be difficult to do this, because a lot of the behavioral things that I'll talk about here are nuance-level.

[23:20] We don't often think about them purposely, but we know in the back of our heads something is off if it doesn't work the right way. It's like that.

Interviewer: [23:27] It's like the uncanny valley of UI.

Chance: [23:31] Exactly. I'll just narrate what I'm doing as I do it to illustrate some of these things. With a native select menu, and this is on macOS, it's a little bit different on Windows, which is its own other annoyance, but nonetheless, on macOS, if I were to...It's also different between browsers, so these get really funny. If I were to click on this guy, so I just moused down but I have not yet moused up.

[24:04] The click event actually doesn't fire until after mouseup. The sequence is mousedown, mouseup, click. Right out of the gate, most people are going to say, "When you click on your select, open it." Like fire that on a click event. Reach UI decides to mimic native behavior and fire on mousedown.

[24:27] The nice thing about that, the reason that's an important nuance is that, and I do this a lot, I don't know that everyone does this a lot, but when you use a component, when you use an element natively on the Web, you start getting used to a lot of these small behaviors and you don't even realize that you're used to them.

[24:47] Your behavior adapts to what you expect to happen. If I use this enough and over time I'm used to responding to this on my first mousedown, I might notice that if I hold my mouse down and I move my mouse over an option and now I mouseup, that it selects another option. You can't do that on a click event because this thing never even opens until after mousedown, mouseup, click.

[25:14] Right out of the gate, Ant Design actually does this right. If I mouse over the button, it works perfectly. However, nothing happens when I drag my mouse over another option. There's not another option.

Interviewer: [25:32] I've experienced this annoyance personally. I know what you're talking about. You open it, it just doesn't work how we've been conditioned to use it.

Chance: [25:45] The tricky part here is that even though I've moused down I can't mouseup over an option and select it. I have to mouseup. Then I go into a navigating mode. Now you can see the contrast ratio here is absolutely terrible, so I can't actually see what I'm trying to select here. You can't actually do anything until you mouseup and then you go into clicking mode.

[26:08] Even though they've got the mousedown right on the button, they missed the mark on what happens from there. We have a nice little statement machine definition to make that a pretty simple process.

[26:21] The same thing goes if you were to mousedown over an option and now I mousedown over "dog," but I haven't clicked yet, I can still drag and select something. Even though I started on "dog," I can still drag down to "goldfish," mouseup and select "goldfish."

Interviewer: [26:38] We haven't even gotten into keyboards.

Chance: [26:40] No, no, this is very basic mouse stuff. These are the low-hanging fruit of the select component. Still, they're easy to miss as simple as it is.

Interviewer: [26:51] Isn't it an aesthetic choice? Why would we just not use the native?

Chance: [26:58] Yeah, so it's usually aesthetic. There have been a lot of really good...

Interviewer: [27:01] You want control, right? You want stylistically or whatever.

Chance: [27:05] Yeah, so with a select menu, it's notorious for limiting people's ability to do things, whatever they want to do. If I open this, how the popover looks, you're pretty limited to what you can control as far as that goes.

Interviewer: [27:18] Yeah, multi-select. In the Ant Design, they have a tool when you select them they become like the selections in a different...It's disconnected, all that stuff.

Chance: [27:28] The two biggest reasons. There was a nonscientific poll that went around on Twitter a while back. I can't remember where to find it or how to cite it, but the poll basically asked, "Why would you bother redesigning a select menu if you knew that you could just use a select menu?" The two most common reasons are aesthetics and adding functionality.

[27:53] Exactly as you said. If I want nested check boxes, if I want some arbitrary content inside of this thing...

Interviewer: [28:00] Tacos.

Chance: [28:01] Tacos. We try to illustrate that stuff in the Reach UI docs because that's what people need. They need the ability to have these arbitrary things. We have these little tags here. We have our little taco emojis. You could pretty much put whatever you want in there and we still try to make it work as closely to the native behavior as possible.

[28:25] As you indicated, we haven't even touched on a lot of the more complicated and nuanced keyboard behaviors. What do I always do when I'm filling out a form online if I get a drop-down menu where I already know what some of the options are going to be? I won't bother using my mouse because I'm already with my keyboard and I likely just had to use it. I have...

Interviewer: [28:46] It's like the first letter. Like there's all sorts of weird to-dos.

Chance: [28:47] Yeah. If I want to select "dog," I type D and there's dog. I can type G and there's goldfish. I can type literally the whole word and if there's more than one D option, it will continue searching the D options.

[29:04] It'll time out after a certain point, too, so that if I start typing "dog" and then I wait, I don't know, 500 milliseconds, or even 1,000 milliseconds, then it will stop capturing what I'm typing and then register that I'm typing a new word altogether. All of these nuances are pretty tricky to get.

[29:23] If we go back to Ant Design, if I start typing "Jack," Ant Design's weird because every keyboard event opens the menu, which is super annoying. It says, "Hey, we're going to give you keyboard events, but just any key. We don't care what key." I type the letter J and it just opens the menu for no reason, so that's not right at all.

[29:46] Now I can at least navigate up and down a menu, but that's about it. There's no type-ahead whatsoever in this one.

Interviewer: [29:55] That's really interesting. It's a totally different conversation around why. I understand some of the design choices that went into this just because of mainly like Ryan Florence's flurries of investigatory tweets. Like when he would go, "How does a select work?" or whatever, and he would go into detail about his investigation.

[30:22] I don't know if people are skipping that stuff or not. Like the design choice to make it different than what people would always expect is an interesting philosophy of design, maybe. I don't know. I'm being generous.

Chance: [30:42] My personal philosophy on this is you should always try to use the native HTML if you can, if you absolutely must customize it. Here's the thing. People are going to do it anyway.

[30:55] We found this over time that no matter how much we scream and yell about accessibility or about how hard this stuff is to get right, people do it. They often do a bad job. It's not because people are bad developers. It's because they have...

[31:10] [crosstalk]

Interviewer: [31:11] They're trying to get work done.

Chance: [31:12] Trying to get work done. There's a lot of stuff in the next...This list box is a very basic thing that we built. This took me a month to build. This one is about...

Interviewer: [31:21] That's why people retry their design. It's like you're building an app. You go to the box. It's going to take us a month to do this right and make this list box. They're like, "Yeah, no, just use that. Get that done."

Chance: [31:33] Before React jQuery UI had their own thing, jQuery UI did a lot of the same stuff. They've got a select. It's actually not that bad. Even if you're in React, I'd probably recommend you jQuery UI Selectmenu over an Ant Design menu because it works.

[31:52] It does have some additional quirks with it, but it doesn't open on mousedown. It opens on click. That's fine, but I can still type ahead. That's nice. To me, that's the most important thing.

Interviewer: [32:04] It's better.

Chance: [32:05] Yeah. There are a lot of third-party tools out there, but even if you can't spend the time rolling your own, at least spend enough time investigating to make sure that the one you choose to work with is doing a pretty good job at covering those bases. There are good options out there.

Interviewer: [32:23] Honestly, I sent so many people to Reach. I'm like, "Oh, I've seen this in our own app book," or somebody would build something, I'm like, "Is that in Reach? You should just go get that."

[32:33] Then my second recommendation is, do you want to look at some components and get a good idea about component development and state management in React like, "Here is a whole pro-style, top-tier resource"? If you take code and source code as a learning material, you're all doing an amazing job. Thanks for that.

Chance: [32:55] I appreciate that. Another thing that I like about Reach, simultaneously it makes it a little harder to read in parse. Also, if you know what you're looking at, it's a good opportunity to see our timeline, how our thinking in terms of state has evolved over time.

[33:14] Most of these components Ryan wrote years ago. We've adapted them. We've changed it, and updated it, and maintained them, and made sure they work well. The way we architect them has certainly changed a pretty good deal. List boxes...

Interviewer: [33:27] You're saying like you get into the GitHub repo, and you can start scrolling back, and commits, and get a historical context of how this has evolved and some of the thoughts and ideas that have progressed over time, I would think.

Chance: [33:44] Yes, exactly. Tabs was one of the first components that Ryan wrote. It's changed a great deal since he wrote it, but a lot of the fundamental methods he used for managing state have pretty much stayed the same.

[33:56] We don't have any state machine here. There's not a reducer or anything. Most of these components were written before we had Hooks. This one, I believe, was written before we had the Context API.

[34:11] The way that he went about doing a lot of things reflected that time, we've since integrated context. No less, we have a bunch of individual state nodes. Like I was saying earlier, that I would probably usually avoid this once I started having these intertwined, deterministic state nodes. I would probably use a reducer. It works well though. I'm not going to spend the time rewriting code that works.

Interviewer: [34:41] You could refactor this, but you can also just work on new stuff because it works.

Chance: [34:47] Exactly. We do that. It works fine. If you start here and then you work your way through it, like you work your way up in time, you'd have to know which components we wrote first. You can look at GitHub and figure that out if you wanted to. You could see a progression in thinking.

[35:03] We jump over to our Tooltip, which is one of Ryan's older components. There's a lot of nodes in here. This is, I think, the first one that he used a state machine on. We didn't go and pull a next state or any fancy library.

Interviewer: [35:20] That would be a big dependency, and you're trying to be a core library that somebody could bring in without importing the world. We just want to bring this in. That's one of the interesting things about state machines. Next state is a wonderful library. It's probably something that I would bring in the most application applications.

[35:37] If you're building a library, the choice to use another library...He's too opinionated generally to make something that's broadly usable. Is that fair to say?

Chance: [35:47] We do use XState in Reach UI. David has written a much smaller version.

Interviewer: [35:53] FSM?

Chance: [35:54] Yeah, FSM. XState is quite big for a component library, I agree. It's great for an application because you're likely going to have a lot more [inaudible] away. I don't think that's where you're going to bleed in terms of your bundle size.

[36:09] Yes, if you're building a component library, it's probably wise to stay fairly lean. FSM is great because it captures a lot of the important things you get from XState. It doesn't have all the bells and whistles. There are some features we don't have access to. We can work around that. It supervises with many of the same benefits that we're looking for.

Interviewer: [36:28] And compatible with the amazing visualizer, which is his master...

Chance: [36:31] Oh, visualizer is awesome. That's one of the biggest selling points of XState. To me, it's being able to drop your stuff in the visualizer and get into visual feedback as to what you've just applied. You can even write your whole thing in the visualizer, which is also very useful. As you make changes over time, you can always go and drop back in and visualize your updates.

Interviewer: [36:52] It's really cool.

Chance: [36:53] It's very nice. Before XState was a thing and before Ryan had a very firm understanding of state machines, he started like the rest of us. He just started tinkering, experimenting. He wrote his own transition function.

[37:08] That's what we use. It's pretty small, but it does basically the same kind of thing. It takes our current state. It takes an event. It determines what our next state is based on that. Then we have a little state chart somewhere.

[37:26] There we go. Here's our chart. It's a lot simpler than one you'll see in XState. You can drop in the visualizer. It does essentially the same thing. It takes our current state and tells us where to go based on that current state.

[37:39] If we're on idle and we do a mouseenter, we're going to go to focus. We don't have any conditions or anything like that, but it does a good job at capturing some of the basic ideas of a state machine.

[37:51] Then if you fast forward into when I started working with the company, I built Accordion which was also before I understood state machines very well. The first component that I built with the state machine was our list boxes, just like that.

[38:11] If I were reading Reach UI or I was telling someone to go check it out for inspiration on state management, I would suggest looking at the commit history and identify the timeline as well, because the timeline is very indicative of why we made certain decisions when we made them.

Interviewer: [38:31] That's a pretty cool project. It's a learning exercise, like learning how to analyze a library like this and go back and do the anthropological digging that you would need to do to fully...I can ask you, right? You're here talking to me on Zoom. We can discuss it. I can ask some questions. There's awesome value in that.

[38:54] The idea of going in and taking the...We have this amazing record with Git and analyzing that and doing a study through the progression of a component library, just thinking purely from a learning standpoint of what depth you could potentially achieve if you went in there and took that seriously. It's a serious course of study. It's pretty interesting to me.

Chance: [39:17] That's the only reason I was able to work on Reach. I don't work full time with them anymore. The only reason I feel like I was qualified for the job is because I spend a ton of time on my own investigating how it works. That was such a great library. It was my go-to before basic components for a long time.

[39:39] I thought one day...I don't remember when it was, but it was back maybe last June or so. I looked at Reach and thought they're not doing anything with it anymore. It's a shame, because it's such a good library. I wonder if they need some help.

[39:54] Without communicating with anyone, I just said I was going to write an Accordion component and style and model it after Reach UI, model it after the other components and follow a lot of their patterns.

[40:05] I did this in the dark, on my own and totally randomly ran into Michael Jackson at React Rally in August. I met him briefly after I moved to San Diego. We were chatting. He was like, "We're thinking about bringing somebody on to work on Reach UI. Do you know anybody?"

[40:25] Actually, he showed this Accordion that I wrote and see what you think of it. I literally just wrote a Reach component and didn't tell anybody until that day. First person I told happened to be Michael. That's how it started.

Interviewer: [40:43] It's funny. People struggle, right? I know a lot of people, they would desire to be more involved with open source. One of the big sticking points is I don't even know where to start. I wouldn't know how to do that. A lot of that is this lack of context.

[41:01] I love that. I love the notion that you went back through, were inspired, didn't have any end game in mind. You just wanted to practice, I assume, and build a component. This was an inspiration. You did just that.

[41:15] Where does that lead you is now you're a core contributor. You're employed and got to work with them for a period of time. I'm sure that didn't hurt your next steps in your career. You chain most events together.

[41:28] It's like this curiosity and exploration of history and understanding why something exists without having to quiz somebody or go bother anybody to get answers from them. It's there. It's there for you to discover. That's cool.

Chance: [41:42] You can get a lot of that naturally over time just doing your day-to-day job, hanging out. I think it'll take a lot longer. I can't even imagine being this capable in a library like this, or in a project like this, or even my current role at Modulz. I couldn't even imagine doing that two years ago.

[42:04] The fact that it wasn't even two years ago still blows my mind. If I were to just stay at my old agency gig and progress naturally, slowly on the day-to-day, that would've drawn out that process exponentially.

Interviewer: [42:18] Yeah. It's like a research project that totally leveled up your whole career game at the end of the day. You start stretching it out however long you're working in this space. That's a pretty good one. I like that a lot.

Chance: [42:32] Great.

Interviewer: [42:34] What's the heart of this? What's your favorite part in terms of this list box input and how state is being managed? Is the state machine the joy of the thing? Is that the heart of it?

Chance: [42:49] The joy for me is using it, obviously.

Interviewer: [42:51] Yeah, because it works how you want it to, like it should?

Chance: [42:53] The code is fine. It's good. I like the code. It's a pretty good code. We made some tradeoffs to get it out the door as you always do. I know that there's still places that can be improved.

[43:03] Like I said, it's a very complicated component. There's a lot of stuff that we still haven't hit that I plan on hitting. There are plenty of to-dos mocked up into code. Still, when I use this compared to using pretty much anything else that I can think of, I generally come away realizing that ours is better. That's awesome.

Interviewer: [43:27] It's better by design too. It's not better by accident. It's not some sort of happen stance that this was achieved. This was designed, to me, fundamentally. People think of design in the taco emoji sense, the visual sense.

[43:41] This was designed. Meaning, this didn't occur by accident. This was something that was methodical, thought through, and designed with the users in mind at the end of the day. That's why you end up with something really nice, is because it was thinking about the holistic process, and not the quality of the code, and not all of that stuff.

[44:00] It's about, what is the experience going to be of the user? To me, that's at the soul of this entire project at the end of the day.

Chance: [44:10] Yeah. It's funny because we don't care about design in Reach UI in terms of how it looks.

Interviewer: [44:16] It's all design.

Chance: [44:18] As part as visual design goes, everything is just barebones. The idea is we want you to be able to do whatever you want with it without having to override our opinions.

Interviewer: [44:26] It's not material UI or some other...

Chance: [44:29] Exactly. It's absolutely designed from a component standpoint. These are all silly, but they illustrate the things that you can do. We've got these group labels. They're not...

[44:41] [crosstalk]

Interviewer: [44:43] Even the visual design, it's almost clunky in a sense. To me, that's a feature though. I don't get distracted by the visual design of these things. It's like, "Oh, we're going to have to change that." Yes, you are. That's up to you.

[44:53] That's not what we're talking about. This is behavior. We've designed the behavior and, of course, the underlying accessibility motivation just to take in these hard components and making them to where I can drop it in my application. Now, other people get to use it. It just works like it should.

Chance: [45:11] Yeah, works with screenwriters. It's fantastic.

Interviewer: [45:13] It's really good. Cool stuff. Chance, I appreciate you taking the time out of your day to sit down, chat with me about and show us this cool library and what makes it tick.

[45:24] We'll take this and distribute it, but I hope people think about that and the project in terms of the anthropological dig through interesting projects to learn and grow. It's such a good hack and one I think that will get leveraged a lot. It's cool stuff.

Chance: [45:46] I totally agree. It's a cool idea for you to go out in this exploration on your own too. One of the things I love about Egghead is I feel like you guys naturally attract the various curious types who are going to do that sort of thing. That starts at the top. You've recently started exploring state management, and CSS, and all of these things.

[46:09] It's like here's a guy who is extremely successful, who's been at this thing for years. You could literally probably sit back and do nothing, but you're just naturally curious. You want to do this stuff. You want to get better. It's boring. Why would you want to do that? The fact that it starts there is so cool and good on you for keeping at it.

egghead
egghead
~ just now

Member comments are a way for members to communicate, interact, and ask questions about a lesson.

The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io

Be on-Topic

Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.

Avoid meta-discussion

  • This was great!
  • This was horrible!
  • I didn't like this because it didn't match my skill level.
  • +1 It will likely be deleted as spam.

Code Problems?

Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context

Details and Context

Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!

Markdown supported.
Become a member to join the discussionEnroll Today