Consider this scenario, we have a React component that shows a subscription form, the user can move on to phase 2 of the form by clicking a button. The first phase takes a name and email address. Once the user enters an email, the component will silently check if they are a member, because if they are not we want to follow up by emailing them a registration link after they complete the final phase of the form.
This means that we need to call some extra logic if they are not a member, so let’s think about what that might look like:
|
1 2 3 4 5 6 7 8 |
// inside Form.tsx component const onSubmit = () => { sendFormData() if(!isMember) { sendRegistrationLink() } } |
Now we need to decide how we are going to track whether or not the email address entered has been identified as a member. Should we use state? Let’s take a look at what this would look like.
|
1 |
const [isMember, setIsMember] = useState<boolean>(false) |
Then we could call the setter inside a callback which would be provided to the onClick of the form element that completes phase 1. But there is a potential issue with this…when we set isMember using setIsMember, this will trigger a component rerender. Why is this an issue? Well you might not even notice the extra render, and think no big deal, but the browser is having to do some work with each render, so we should think about whether or not we actually need this rerender to occur.
In this case there is no benefit to having this additional render, and simply put, this is because the visual representation of the form does not change. And this is because – from a users POV, the operation of checking their membership status is abstract, therefore no indications nor interactions are needed regarding this evaluation.
What can we do instead? Let’s consider a mutable ref.
|
1 |
const isMember = useRef<boolean>(false) |
And this becomes more efficient because, mutating a ref in React will not invoke a component rerender, and as we have already established, we don’t need a rerender for this. And we can set this like so:
|
1 2 3 4 |
const loadPhaseTwo = () => // stuff isMember.current = //something that checks } |
Then later on in our submission callback we can check this:
|
1 2 3 4 5 6 7 |
const onSubmit = () => { sendFormData() if(!isMember.current) { sendRegistrationLink() } } |