We'll create two simple applications which will display filtered data. Both will use the reactive primitives of each ecosystem. By doing this we'll see the most important differences between react hooks and angular signals.
Transcript
We're going to learn the differences between React hooks and Angular signals reactivity models by implementing two similar very simple applications, one in React and another one in Angular. So they're going to display a list of objects and allow us to filter them. The datasets in both applications are the same and they are hardcoded and same with the components. The properties available are hardcoded, not reactive. For this reason currently the filtering doesn't work and the same in the Angular one right here.
So let's start with the React application and let's make the properties and the data reactive. So we'll need to create a piece of state. And for this reason, we're going to use the useState hook, which creates one property, one piece of state that is going to be available for our component. So let's call it availablePeople which will determine all the available objects that can be listed and setAvailablePeople so the setter. Whenever the setAvailablePeople is invoked with a new value, this component would have to re-render the standard way as it happens in React.
So we would need one more piece of state to determine what is the current value of the status filter. So let's call it status filter and accordingly set status filter and let's provide the default value which is going to be all so whenever all is chosen none of the values are going to be filtered out. Now we've got the duplicate identifier so we're going to remove the hardcodes step by step. Now whenever the status filter changes we would like to update the React component. So whenever there is the native event, we would invoke the update status filter.
So we'd need to call setStatusFilter here. And depending on what the event is, event.target and here comes the value which will basically change our status filter whenever there is a change event taking place on the select. Now in React, if we want to create a piece of state which is going to depend on another piece of state, we don't use that useState hook, but we should make it a derivative. So whenever any of them changes, this value of visible people should also change. And for this reason, we're using the useMemo hook.
So here, we're just going to return what are the available people filtered by whatever the status filter is. So just to make it compile, I'm just going to return the available people. And as you can see, TypeScript is failing because it expects two arguments and just received one. Because we need to explicitly pass what are the dependencies. And We are responsible for passing the dependencies.
So we need to say, tell TypeScript and React that actually whenever any of these change, the useMemo is going to recalculate whatever the visible people are. The thing is, we are responsible for passing whatever is here. So we're going to filter what are the available people. And for a single person, if we've got the status filter which equals all, this is going to be okay for a certain person to be available in the result collection, or if the person's status equals whatever is the current status filter. So what is important here is that first we have to explicitly pass what are the dependencies for useMemo to be re-evaluated and the second thing since both available people and status filter so the value returned from useState this is already the value so there is no getter function this is already the value itself.
One more thing what we should do which is a good practice in React is actually we should not recreate callbacks on each call, so we should also take this callback and wrap it with a useCallback call and again in this case we have to pass what are the dependencies here. So useCallback should recreate the underlying callback whenever any of the ingredients change and in this case this is going to be setStatusFilter. A slight issue with this approach is that if we pass explicitly what are the dependencies, we need to make sure that they are correct. There is a ESLint rule that checks this, but again, this is something that we have to pass, and this is going to be different in Angular. So now, let's take a look if this works, and it works as expected.
So now let's move to Angular version. So let's start with creating the available people equivalent, which in Angular, this is just going to be a signal. So the signal's initial value is going to be people. So let's also turn the visible people into a signal And what we can see already is that there is a type error, a run type type error, that is caused by the fact that a signal is not yet a value as if it was in React, but this is a function that has to be called. So a signal has things like set method, update method, as read-only method, et cetera, but if we want to get the value, we need to basically call it because a signal is always a function.
Now, this is working back again, and we're going to move the status filter to become a signal as well. So we will make it a signal. That initial value is going to be all and the visible people is going to be a derivative which will depend on both available people and the status filter so a derivative in Angular is called computed. Logically, this is equivalent to useMemo in React, however an important difference, as you can see, is that there is no need to pass the dependencies over here. So we just return what the value is here.
So since available people is not just a variable but is a property available on a class, we need to access it via this dot available people property. And again, as said before, Available people is not yet the value but is a signal so if we want to access the value we need to Invoke it because this a signal is a function now since this is already an array We can invoke filter and for a certain person. We can basically copy the logic and again if currently chosen status filter is all then we're going to pass a certain person object to the result collection so this dot status filter if this equals all then the object will reach the target collection. Otherwise we'll have to check whether a person.status equals and again we're going to compare it to this.statusFilter, but again, this is a function which has to be called, so this is correct, but not calling the function is not correct, and even TypeScript can see it because there is absolutely no overlap between string, which is the person.status, and a writable signal, which is the this.status filter, which is not yet called. We just need to remember that we always have to call the value.
Now, the only thing that we are missing here is that we've got an updateStatusFilter method bound to the select, but we are not yet making use of it. So we need to write the logic here. So what we need to do is this.statusFilter, and whenever the value of statusFilter changes we'll use this method. So here we're using the even.target and since we don't have better types we'll just use HTML.selectElement and from the selectElement we're going to use what the value is here. Let's check whether this works.
So when we choose hired the objects are filtered by hired status and for fired the objects are filtered by fire status. So to wrap up the important thing about React hooks is that we need to pass explicitly what are our dependencies whenever something changes And the interesting and very convenient feature of angular signals is that we don't have to pass those dependencies. The way it works is that whenever a computed is being recalculated, signals, by accessing them just by reference, They are not yet called so they are not being read. Only when we actually invoke the signal function, this signal is aware of who is reading it. So this signal will store the reference to the computer, so whenever the status filter value changes, it will basically push a notification to the computer saying, hey, my value has changed, so whenever anybody calls you, bear in mind that you need to update yourself.
And there is also one more thing that we need to do, is basically to call the status filter over here, so that this one is displayed correctly. So, signals keep track on what are the dependencies between each other and in React, unfortunately, we have to pass it explicitly.