React Synchronising Side-Effect With App State

What we want to keep in state Data fetching Data as streams What do we want to keep in state? When a value got changed, React is going to re-render the page. React also tries to avoid unnecessary re-renders. The state should be with values which when updated we will want to update the DOM. […]

by Mirela Tsvetkova

January 11, 2022

4 min read

pexels photo 4164418 - React Synchronising Side-Effect With App State
  1. What we want to keep in state
  2. Data fetching
  3. Data as streams

What do we want to keep in state?

When a value got changed, React is going to re-render the page. React also tries to avoid unnecessary re-renders. The state should be with values which when updated we will want to update the DOM.

1 7 - React Synchronising Side-Effect With App State

this.setState is asynchronous. If increment function becomes

2 6 - React Synchronising Side-Effect With App State

The final value for the counter is going to be 5. React won’t change the DOM on every line that updates the state. Instead, it will wait for the function to finish and then it will figure out what changes need to happen. At the first line reads set counter to 0 + 1, on the next line 0 + 5. It’s happening because we’re passing an object and the operation is similar to Object.assign and spread operator, the last object wins

3 6 - React Synchronising Side-Effect With App State

Because we can’t merge functions but we can pass a function and the function will work as expected.

5 6 - React Synchronising Side-Effect With App State

Data fetching

6 6 - React Synchronising Side-Effect With App State

useEffect is a hook that allows us to maintain the side effects in the application. If we remove the dependencies array, the effect will run on every render. If it’s empty [] ( like in the example ), it will run only when the component gets mounted. When we put dependencies [location, userName] it will execute when some of them update.

On every refresh, we have a new number:

YouTube

By loading the video, you agree to YouTube’s privacy policy.
Learn more

Load video

PGlmcmFtZSB0aXRsZT0iTW91bnQgQ29tcG9uZW50IiB3aWR0aD0iMTIwMCIgaGVpZ2h0PSI2NzUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS1ub2Nvb2tpZS5jb20vZW1iZWQvMVU1cUM2THQwcjA/ZmVhdHVyZT1vZW1iZWQiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZTsgd2ViLXNoYXJlIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+
7 6 - React Synchronising Side-Effect With App State

The code is trying to achieve numbersapi.com with a random number. Before the request we set the loading value to true and when the response comes it switches back to false, the number is saved in the array numberArr. If we want to get a new number when we click on a button, we might give some variable in the dependencies array. We have to define when we want to run the effect again.

YouTube

By loading the video, you agree to YouTube’s privacy policy.
Learn more

Load video

PGlmcmFtZSB0aXRsZT0iTG9hZGluZyBzdGF0dXMgYW5kIGFzeW5jIHJlcXVlc3QiIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjY3NSIgc3JjPSJodHRwczovL3d3dy55b3V0dWJlLW5vY29va2llLmNvbS9lbWJlZC9WQnVPcExTMlRmWT9mZWF0dXJlPW9lbWJlZCIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgY2xpcGJvYXJkLXdyaXRlOyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlOyB3ZWItc2hhcmUiIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4=

We can move the random number in the state, and to get a new one when we click on the button and then fetch the number:

8 4 - React Synchronising Side-Effect With App State

If we open the console now, we’ll see that the Number component is re-rendering multiple times.

YouTube

By loading the video, you agree to YouTube’s privacy policy.
Learn more

Load video

PGlmcmFtZSB0aXRsZT0iUmUtcmVuZGVyaW5nIiB3aWR0aD0iMTIwMCIgaGVpZ2h0PSI5MDAiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS1ub2Nvb2tpZS5jb20vZW1iZWQvYTd4NUU3SFcxTGs/ZmVhdHVyZT1vZW1iZWQiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZTsgd2ViLXNoYXJlIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+

If we use React.memo which will only re-render the component when some of the props become changed.

9 2 - React Synchronising Side-Effect With App State
YouTube

By loading the video, you agree to YouTube’s privacy policy.
Learn more

Load video

PGlmcmFtZSB0aXRsZT0iUmVhY3QubWVtbyIgd2lkdGg9IjEyMDAiIGhlaWdodD0iOTAwIiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUtbm9jb29raWUuY29tL2VtYmVkL19GTkhRcGFwLW1FP2ZlYXR1cmU9b2VtYmVkIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImFjY2VsZXJvbWV0ZXI7IGF1dG9wbGF5OyBjbGlwYm9hcmQtd3JpdGU7IGVuY3J5cHRlZC1tZWRpYTsgZ3lyb3Njb3BlOyBwaWN0dXJlLWluLXBpY3R1cmU7IHdlYi1zaGFyZSIgYWxsb3dmdWxsc2NyZWVuPjwvaWZyYW1lPg==

Data as streams

Instead of thinking about the data as a collection, we can imagine them as streams. With iterators, we can request data one at a time, while with an observer pattern the data arrives over time. If we want to search for a specific number and we use the same fetchNumber function and useEffect and add input field.

10 2 - React Synchronising Side-Effect With App State

And if we are interested in 2385, we type 2 then 3 then 8 and 5.

Request on every type

YouTube

By loading the video, you agree to YouTube’s privacy policy.
Learn more

Load video

PGlmcmFtZSB0aXRsZT0iUmVxdWVzdCBvbiBldmVyeSB0eXBlIiB3aWR0aD0iMTIwMCIgaGVpZ2h0PSI5MDAiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS1ub2Nvb2tpZS5jb20vZW1iZWQvblc0ZjNiTWNwNEk/ZmVhdHVyZT1vZW1iZWQiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZTsgd2ViLXNoYXJlIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+

On each input, we send a request. There is a race condition. We send the request but the expected result might come before some of the previous. 235 can come later than 2385. With the help of RxJS Library, we can find a solution. fromEvent is a function on which we are passing the target — a form, a button, a document and the event that is going to be emitted from the target — click, scroll, etc. Interval is a function that will suspend the emitting of the observable.

11 2 - React Synchronising Side-Effect With App State

The observable is an object with forEach function and this function accepts an observer, which is an object with 3 functions — onNext, onError and onComplete. In React when we want to keep track of an HTML element — div, input, etc. with the hook useRef we won’t modify the defined piece of the state through the life cycles.

12 2 - React Synchronising Side-Effect With App State

The events that we’re going to listen to are onKeypress and onChange. We are passing to fromEvent the ref and the event we’re interested in and then we merge them. Throttle instead of returning immediately the observable will wait the defined amount of milliseconds before another one comes, if it arrives then the previous gets thrown. If no one arrives after 300 milliseconds, it goes forward.

13 - React Synchronising Side-Effect With App State

But this only fixes the problem with network requests.

2385 Unsuccessful

YouTube

By loading the video, you agree to YouTube’s privacy policy.
Learn more

Load video

PGlmcmFtZSB0aXRsZT0iMjM4NSBVbnN1Y2Nlc3NmdWwiIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCIgc3JjPSJodHRwczovL3d3dy55b3V0dWJlLW5vY29va2llLmNvbS9lbWJlZC8tYUgweGVib3kxZz9mZWF0dXJlPW9lbWJlZCIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgY2xpcGJvYXJkLXdyaXRlOyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlOyB3ZWItc2hhcmUiIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4=

If we change the throttle with switchMap. So if we start typing and clicking, the request to the API will be only the latest one. The observables have to clean after themselves, we do this in useEffect hook. Ben Lash says about useEffect and unsubscribe in his post “useEffect already has cancellation ala “switchMap” to some degree. When it returns it’s going to register a teardown function and if you provide dependencies they will trigger it to resubscribe and then it will register a new teardown:

14 - React Synchronising Side-Effect With App State

2385 Successful

YouTube

By loading the video, you agree to YouTube’s privacy policy.
Learn more

Load video

PGlmcmFtZSB0aXRsZT0iMjM4NSBTdWNjZXNzZnVsIiB3aWR0aD0iMTIwMCIgaGVpZ2h0PSI5MDAiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS1ub2Nvb2tpZS5jb20vZW1iZWQvQjdPUDdYWllNaTQ/ZmVhdHVyZT1vZW1iZWQiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGNsaXBib2FyZC13cml0ZTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZTsgd2ViLXNoYXJlIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+

The last optimisation that we can do is to make a call to the API only for new values. useCallback is a hook to which we pass a function that only will run if the property changes.

15 - React Synchronising Side-Effect With App State
YouTube

By loading the video, you agree to YouTube’s privacy policy.
Learn more

Load video

PGlmcmFtZSB0aXRsZT0idXNlQ2FsbGJhY2siIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjkwMCIgc3JjPSJodHRwczovL3d3dy55b3V0dWJlLW5vY29va2llLmNvbS9lbWJlZC9yOGNheTJLaGYtQT9mZWF0dXJlPW9lbWJlZCIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgY2xpcGJvYXJkLXdyaXRlOyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlOyB3ZWItc2hhcmUiIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4=

Categories

Middle Software Engineer 1 at Dreamix