Day 4 - June 30, 2022

Topics Covered

  • Validating component properties
  • Event handling
  • Event pooling and synthetic events

Validating component properties

You can think of property validation in components similar to field validation in HTML forms. The goal is to inform developers implementing a component that they have provided a value that is not acceptable. This improves the experience for developers that are interacting with components you have created.

Type Validation:

The prop-types package includes simple property type validators that can handle most primitive types of JavaScript values. You will use these validators frequently to ensure property values contain the expected data type. It is worth noting that if you do not pass a value to a given property, the type is not validated and no warning is displayed.

Code Example

Copy and paste the following code example into VS Code then try changing the property values so they use the wrong types. For example, change line 45 to read myBool={"false"}. You should see an warning similar to: Failed prop type: Invalid prop `myBool` of type `string` supplied to `MyComponent`, expected `boolean`.

Required Values:

As mentioned earlier, no warning is shown if you simply ignore a property but there are times when a value is required. Using the prop-types package, we can indicate the values that must be specified. Let's modify the previous code example to require all properties be specified.

Code Example

Any value:

Sometimes you don't know (or care) what type of property is passed to your component but you want to ensure something is passed in. In otherwords, it is a required property but the data type doesn't matter. This is easily accomplished using PropTypes.any.isRequired.

Specific types:

If you need a property validator that checks for a custom type defined by your application, for example a component called MyComponent, there are PropTypes for this as well.

  • PropTypes.instanceOf(MyComponent) - requires an instance of MyComponent.
  • PropTypes.oneOfType([PropTypes.string, MyComponent]) - requires an instance of string or MyComponent.
  • PropTypes.arrayOf(PropTypes.instanceOf(MyComponent)) - requires an array of MyComponent instances.

Specific types:

So far all of the validation checked the type of property but the actual value may be just as important.

  • PropTypes.oneOf(possibleValues) - Checks the property value and warns if the value is not contained in an array possibleValues.
  • PropTypes.shape(comparableObj) - Similar to instanceOf() but we don't care about the actual type. Instead, we care that the object passed in has all of the required properties and that each property is valid.

Custom validators:

The validators provided by the prop-types package cover a wide range of scenarios but you may require some sort of custom validation logic. Simply define a function accepting thre arguments (props, name, component) => { }. Return null if the value is valid otherwise return an Error instance.

Code Example

Event Handling

An event handler is a callback function that is triggered once an event takes place. For example, this could be a button click or when the value of a text box is changed. In React, we can configure event handlers on components by modifying the JSX. Let's take a look at a simple example. When the button is clicked, the status is changed from Waiting to Clicked.

Code Example

You can see that an event handler is attached within the JSX by adding the apprropriate attribute. In the previous example, we have added onPress={e => setStatus("Clicked")} to the <Button> component. The handler is defined inline using arrow function syntax.

When you assign an event handler, React adds the handler to an internal dictionary of events and functions. Tracking events in this way allows React to keep the declarative UI structures separate from the platform we are running on. For example, if we are running our App in a browser, events are not attached to the underlying DOM element. Instead, there is a single event handler on the document. Once fired, an event bubbles up through the tree to the document. React sees the event, checks it's internal mapping, then runs the appropriate function. It may seem like alot of effort but the benefits are plentiful. Since we don't rely on the DOM (or the specifics of the OS), we can wire up events using the same method on all platforms.

As we just learned, we will define events directly in our JSX markup. React uses a declarative approach for setting up event handlers. An advantage to this approach is that event handlers in JSX markup are part of the UI structure. If you compare this to something like JQuery, in JQuery you write imperative code that selects the relevant DOM element and attaches event handler functions. You are left no choice but to track down code that assigns event handlers making debugging and understanding program flow more difficult.

In the code example above, the event handler was coded inline within the JSX using arrow function syntax. This is handy if your function is simple but there are times when you need to perform multiple opeations or add complex logic. In these cases, you can move the handler logic to a separate function, then call that function instead.

Code Example

It is also possible to pass arguments to event handlers. In the following code example, we are rendering a list of buttons using the objects contained in the players array. When a button is clicked, the text is replaced to include the name of the player object associated to the button that was clicked. This code example combines many of the topics we have learned so far.

Code Example

Event Pooling

We discovered that events are bubbled up and handled by an internal mapping system. This allows for a more uniform apporach for handling events that can be shared across different browsers or devices. Even if we manually add new event listeners using JavaScript (rather than directly in the JSX), React will wrap event handlers to ensure event propagation works correctly. These wrapped events are called Sythentic events.

If all events, native or synthetic, are being handled by React, this could cause a bottleneck in performance. Furthermore, synthetic events will need to be cleaned up (garbage collected) at some point which can cause further performance issues.

Garbage Collection
A form of automatic memory management in which the program tries to free up memory space that is no longer being used. When the garbage collector is running, JavaScript code is paused adding potential delays.

React deals with this problem by creating a pool for handling synthetic events. Whenever an event is triggered, it uses a slot from the pool. when the event has completed, the slot is released and can be reused again later. This prevents garbage collection from running too frequently especially when alot of events are triggered in a short period of time.

There is a small problem that should be noted. If the synthetic event handler invokes some asyncronous code, the event will finish up rather quickly and get returned to the pool. When this happens, the properties associated to the event are cleared up. If the asyncronous function accesses any of these properties they will not be available.