Blog Hero Background

1 of 3 How is state related to the declarative approach in React?

If you're newer to React and some of the main ideas like how state and declarative approaches escape you, then chances are you need to read this. For many newer React developers, terms like "declarative" might seem academic and so these concepts are skipped over. But they're actually the key to unlocking the more advanced knowledge down the road.

User Avatar
Brad WestfallSay hi on Twitter
May 13, 2021

Upcoming Workshops

3-Part Series

The "React way" of doing things is to re-render your component whenever you want to create a new set of instructions for updating the DOM. In other words, you'll year people say "UI is a function of state" and when state changes, the UI will change accordingly with a re-render. In React, the term "re-render" simply means that our component function is called again to produce a new set of UI instructions based on the new state.

Let's take a look at some non-React code to start to see how we can think in terms of a function getting called to produce new UI:

function makeDiv(x) {
return `<div>${x}</div>`

You can see that we just need to call makeDiv('hello') if we want to get the div string back with "Hello" inside. If we want to think about the argument as being "stateful" and can change, imagine we have to call the function over and over again:

let message = 'Hello'
message = 'World' // state change

This is a good start for how to think about React regarding interface changes due to state changes. In React, the difference from this is that the state is "local" inside the function instead of being passed as an argument. So, instead of us explicitly calling the function when the state changes and we want new UI, the component function call is more implicit when we change state with a setter function.

The initial render of MyComp in this example will produce <button>0</button>. This is because the call to useState takes an initial state argument and then returns that to us and we called it count.

function MyComp() {
const [count, setCount] = useState(0)
function add() {
setCount(count + 1)
return <button onClick={add}>{count}</button>

Then when we click the button, here's the series of steps that takes place to update the UI:

  1. The onClick calls the add function which calls setCount.
  2. Doing this will not mutate (change) the count variable for the rest of the scope of add. Instead, calling setCount will lead to React calling MyComp() again (which is the re-render).
  3. In the subsequent call to MyComp, calling useState is the first thing that happens again and this time it returns out latest state where count is now 1.
  4. The end result is we return <button>1</button>

Notice that we don't think it terms of "Events change the UI". Instead, we think "Events lead to state changes and those state changes cause re-renders which lead to new instructions being given to React to update the UI".

Had this been jQuery or vanilla JS where we do think in terms of "Events change the UI", we might have:

function add() {
$('.some-button').html(count + 1)

The jQuery example uses the event to directly reach out to the DOM we means we need to think in terms of the event and how that turns into a UI update. We would say this is "imperative" doing it the jQuery or vanilla JS way because we have to orchestrate exactly how the UI change is implemented. Earlier when we called makeDiv('hello'), we would get a string returned and we would somehow figure out how to turn that into a DOM node and how to place it in the spot we wanted.

All of that is "imperative" because of the how parts.

In React, we tend to prefer the "declarative" approach more where we can say:

"This is my current state. React, here is an instruction for what I want made. I don't care how it happens, you figure it out!"

Then React makes it happen in the DOM. Later when the state changes:

"Okay React, I have some new state, and here is my new JSX instruction for what I want made. You figure out how to update the DOM"

React will make that DOM update for you when you return what you want with JSX. This is what we mean when we say "React allows us to update the DOM declaratively".

But what if I need update something imperatively?

If you want, you can update the DOM directly (imperatively) in React too. We mostly use "refs" for this which allows us to make and store a reference to the DOM. That's out of scope for this series though.

In general we try to prefer the declarative approach first until it becomes obvious that we need to use an imperative approach. The reason is that with React, so many things happen for you for free when you embrace the declarative approach. Whereas with the imperative approach, you're mostly on your own.

Photo by Kumiko SHIMIZU on Unsplash

Subscribe for updates on public workshops and blog posts

Don't worry, we don't send emails too often.

i love react
© 2024