How to Create Render Props With TypeScript Classes
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
Lesson Transcript
[00:00 - 00:07] Creating render props with classes. We can use classes to create render props components as well. Let's rebuild our provider using the same technique but based on a class.
[00:08 - 00:41] Classes are like blueprint for creating similar entities. In TypeScript, classes can implement interfaces and extend more general classes. For example, we have an interface printable that describes a behavior contract. It guarantees that the entity implementing this interface has a method print. A class can declare that it implements this interface. TypeScript will check if this class has all the methods specified in the interface. If some of the methods are missing, TypeScript will produce an error. Class article incorrectly implements interface printable. Property print is missing on the type, article but required in type printable. We can extend a class and modify its behavior a bit.
[00:42 - 01:01] It is useful when we want to enrich the class's basic functionality. For example, we can specify an additional property. Here it's the word count. To create a new instance of an article class, we call it with keyword new. Every instance is a separate object and can be manipulated separately. So a class is a blueprint and every instance is a separate entity. Isn't it similar to components?
[01:02 - 03:11] It is indeed. As we'll see later, React provides us with a component class that we can extend and create our components based on its general functionality. Basically, component deals with the inner details of a component lifecycle. It determines when to update and rerender, how to create a local state and stuff. Our extensions, components, only define modified functionality. Like the component markup. With all that in mind, let's try and create a class component . Inside of SRC adapters, sound font, create a new file, sound font provider class.ts. At the imports, here we'll need the component class from react, react element type, we'll need sound font, instrument name and player from the sound font player, MIDI value from the node domain, optional from the types and audio node registry and default instrument from the sound domain. Let's define the provided props type provided props is an object where loading is a Boolean flag. Play is a function that receives note is an argument and note is a MIDI value and it returns a promise that resolves to nothing. We basically just say that play is an async function same with the stop. Now let's define the provider props type provider props is a type with an instrument of type instrument name audio context of type audio context type and render that receives props of type provided props and returns react element. Unlike in the previous implementation, the instrument is not optional. That's because we'll use the default props when nothing is passed to a component. We will see how to define them in a minute. Since we'll use a class, we specify a state type because use state hook is not available in the class components. So let's define type provider state loading is Boolean and current is an optional instrument name. Now let's define the sound font provider class expert class sound font provider extends react component. Here we provide the type for the props and for the state provider props and provider state define the default props public static default props and here we provide the default instrument instrument default instrument.
[03:12 - 10:03] Define the private properties private audio is audio context. We don't put it into state because we don't want it to be observable private player optional player by default now private active nodes it's an audio nodes registry and it's an empty object. Now let's define the state public state provider state equals an object with loading false and current now. So we've created three private fields for our class audio player and active nodes and we made them private because we don 't want the outside entities to mess around with those fields. It is considered good practice to mark everything that is not public as private or protected. The difference between private and protected is that private members are accessible only from the inside of this particular class and protected members are accessible from inside of this class and extending classes as well. Now look at the default props here we declared them as a static field on the class that means that they belong not to a specific instance of this class but instead they belong to the class itself. Let's continue defining our class after we have the state let's define the constructor method constructor is going to be called when our class is going to be instantiated it receives props of type provider props calls method super and passes the props there we call the super props to call the parents constructor. So here we call the constructor of the react component class we do this to avoid situations when these dot props are not assigned to a component until the constructor is finished otherwise we wouldn't be able to access audio context from these props in a constructor and we'll need to do this in a second const audio context equals these props so this is why we have to call super props first to be able to access the props attribute now we define this audio as new audio context so far so good now let's imagine our components lifecycle what should occur and when the whole lifecycle consists of three stages mounting updating and unmounting on every stage there are available methods provided by the component class so when we are mounting our component we first call the constructor to instantiate the class then the get derived state from props is getting called and you can override it to use it but to be honest it's used quite rarely then the render method is getting called and then the component did mount and here is where you usually will perform your side effects then there is updating stage and it happens every time the props or the state or the context of the component changes here we again have the get derived state from props method called then shoot component update and here we can prevent the component from updating render method and component did update again we can put the side effects here and on unmounting stage that happens when we un mount our component there is only one method component will unmount here we can clean up all the event listener subscriptions timers and so on in our component we'll define the public method component did mount here we'll perform the side effects and that will mean that we'll get the instrument from these props and then we'll call this lord instrument this method will be loading the sounds let's define this method and mark it private private lord equals a sync it receives an instrument of type instrument name and then it calls this set state and sets the loading to true after we do this we'll get the player this player equals await sound font instrument from this audio and the instrument after it's done and we have the player we call this set state loading false current instrument after we've loaded the instrument when component was mounted it's time to define the shoot component update public shoot component update it will receive the instrument prop provider props we'll use this method to prevent updates and re-renders of this component if the new instrument that we passed to it is the same as the previous one so we return this state current not equals to instrument so if it is a new different instrument then we'll allow to update the component otherwise we'll do nothing and then let's define component did update public component did update it receives an instrument that will rename to prep instrument the type of the props is provider props and then inside of the method we'll get the instrument from the props instrument equals these props and now if instrument and instrument is not the same as pref instrument then we call this lord instrument now we'll need two other methods to implement and expose that means that they're going to be public public method play it's an async method that will play a note of type midi value here we call await this resume and then if there is no player then we return we'll have to use the resume method both in play and the stop methods so let's define it here private method resume is an async method that will check if the audio state is suspended then it will call audio resume otherwise it will just resolve a promise now let's continue with the play method so if we have a player then we get the node it's this player play node to string it will generate an audio node and will actually play the node and then we add this node to the list of active nodes this active nodes equals this active nodes plus new node accessible by the node let 's define the stop method public stop equals async node midi value in the beginning we also call resume await this resume if there is no node in the active nodes this node active nodes accessible by the node then we return it means that there is nothing to stop otherwise we call active nodes by node here we assert that the value exists because we already checked for its existence online 86 and then we call stop this active nodes equals old value of this active nodes and we set the node by the node name to null so we remove it from the active nodes list finally don't forget about the render method it's mandatory and we actually need to render the render props public render const render from the props this props const loading we get from the state this state and now we return render where we pass loading play this play and stop this stop as you can see in this class provider the final interface is exactly the same as in the functional if you scroll down you will see that we still pass the loading play and stop to the render prop both in the functional sound provider and in the class version.
This lesson preview is part of the Fullstack React with TypeScript Masterclass course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack React with TypeScript Masterclass, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
![Thumbnail for the \newline course Fullstack React with TypeScript Masterclass](/_next/image?url=https%3A%2F%2Fs3.amazonaws.com%2Fassets.fullstack.io%2Fn%2F20220425171607321_CoverImage_FSReactWTypeScript_Masterclas.png&w=3840&q=75)