Well, I have appinions_

DIVIDE BY Z3R0

🍔

Reactive state machine

Reactive state machine

There are many ways to describe React as a library. My personal description of React is “reactive state machine.” But first things first—on the blog photo, you can see a prime specimen of a seasoned React developer. Yes, that is how we look. Now, back to business. Since React is a declarative library, it uses states to DECLARE what we want. And using those states, it performs some effects (reacts to state changes). So, besides handling effects, one of the most important things to figure out when it comes to developing React SPAs is how this state should be managed. We have a lot of tools at our disposal, so let’s cover some of them, when they are a good choice and why, and how to use them.

useState

If you are a React junior with 2 weeks of experience, you’ve likely come across useState. It’s a rather simple hook that gives you a tuple of a state getter and a state setter. Here are a few common states with their most common types.

const [loading, setLoading] = useState(false)
const [userData, setUserData] = useState({})
const [groceryList, setGroceryList] = useState([])
const [userId,setUserId] = useState(0)

So, as you can see, we have a tuple, and as an argument, I passed false, an empty object, an empty array, and the number 0. I didn’t have to pass anything, but I personally prefer to pass a type during the initialization of a state. First, it helps with TypeScript, so you don’t have to declare the type using generics. Secondly, if you’re not using TypeScript, other developers will know what the state should hold or at least have some basic idea.

Moving on to the second tuple variable, you will use it to set the state. The state setter can accept an argument or a callback function.

Example:

setLoading(false) // simple argument
setLoading(previousState => !previousState) // callback function

A general rule is to use a callback function ONLY when you need information about the previous state, since the callback function accepts the previous state as a parameter. And that’s pretty much all about state, but the problem with state is knowing when you should NOT use useState. Does it seem like a silver bullet?

Props drilling.

Props drilling is your worst enemy when writing React code. Since React has one-way data binding, it’s smart to hold logic in the top-level element, meaning the oldest parent possible. And then, right there, the young, inexperienced React padawan (unlike that Chad in the top photo) will encounter their first issue. Let’s explore this code.

const SuperAwesomeTopLevelComponent  = () =>{
    // list of states
    const [loading, setLoading] = useState(false)
    const [userData, setUserData] = useState({})
    const [groceryList, setGroceryList] = useState([])
    const [userId,setUserId] = useState(0)
    
    // Some logic only God can understand and even he is not sure how it works, what it does and why. Besides him, guy on the top photo understands it. 
    // lets just assume when we fetch user data and grocery list related to set user we should pass all that towards granulated componenets
    
    return (
        <>
            <UserDataComponenet loading={loading} userData={userData}/>
            <GroceryListComponenet loading={loading} userData={userData}/>
        </>
    )

}

Okay so far so good.

Now lets explore 2 children components

const UserDataComponenet  = ({ loading, userData }) => {
    if (loading) return <Loader />
    return (
        <UserCard>
            <UserInfo userName={userData.name} userLastName={userdata.lastName} />
            <UserImage  userData={userData.image} />
        </UserCard>
    )
}
const UserInfo  = ({ userName, userLastName }) => {
    if (loading) return <Loader />
    return (
        <>
            <p>{userName}</p>
            <p>{userLastName}</p>
        </>
    )
}

Okay, that’s a lot of code. User data was fetched inside , then it was passed to . After that, we split it into userName and userLastName inside . Congrats, we have just created an anti-pattern, something the guy in the blog post photo would never allow himself! We drilled props from three levels down. And this is a rather simple component structure—imagine something bigger on a more complex project! How do we solve it?

Redux to the rescue.

One of the oldest ways to manage state across the app and prevent prop drilling is the react-redux library. Redux is a global store that uses a simple provider pattern and two hooks: useSelector and useDispatch. The architecture of Redux can seem overwhelming for beginners, but it’s not that complex. There is a “provider” higher-order component and a reducer, which literally follows reducer patterns.

This demonstrates why learning patterns in software development is so important. Anyone familiar with reducers, providers, selectors, and dispatchers will understand Redux right away. But, since I assume you might not, I’m explaining it here. As I mentioned, Redux is a global store. While it has a lot of advantages, it also has some disadvantages. I’m not going to dive into how to use Redux, as there are plenty of tutorials available online. Instead, I’ll focus on when you should use Redux.

Advantages of Redux:

Global store prevents prop drilling. Extensive support—there are many tutorials and guides. Simplified data flow—you don’t have to track state across child-parent chains due to prop drilling. Modularity—you can split code into logical chunks. Disadvantages:

You lose all state if you refresh the page. There’s a lot of boilerplate code, especially if you don’t have a large number of states. If you only have a few global states, Redux can be overkill.

Browser storage?

Let’s think outside of react box? Lets combine react way with way of the old browser Gods. Now, if there was some black magic tool, provided for us by the browser, and that tool can store stuff for us? That tool keeps it even if app is refreshed or closed? And that tool is there for a while now? Oh imagine, our own browser storage.

Unlike redux, using browser storage like localstorage mitigates both problems of redux. You can have global state for simpler state confugurations, and we dont have a lot of boiler plate code. Actually we just need one simple hook.

const useUserName = () => {
    const [userName, setUserName] = useState(localStorage.getItem("userName"))
    
    const _setUserName = (newName) => {
        localStorage.setItem("userName", newName)
        setUserName(newName)
    }
    
    return {
        userName,
        setUserName: _setUserName
    }
}

And there it is, you have user name accesible all over the app, with one simple hook. You dont have to declare action, you dont have to create reducer, you dont have to create provider. Its sufficient replacement for redux when it comes to less complex states. Simple combination of useState, custom hook and browser api gave us alternative to redux.

Query strings.

Now check this out. I want to share states between multiple computers. Somehow, I want to give my friend the same states as my instance of the app. A real-life example would be sharing a search link with the same parameters. Well, just combine useState and queryString. Simple as that.

Lets say I have searched for Boxing gyms, in the Belgrade area. www.superAwesomeSearchApp.com/search?name=boxing%20Gyms&location=Belgrade

Now here is an example how to do that. You have to READ values from the query and tu put them into state, also, you need to update query when you are changing state Code example would look like this in this simple hook.

import { useSearchParams } from "react-router-dom";
const UseParamsManipulation = () => {
  const [searchParams, setSearchParams] = useSearchParams(); // Hook to access and manipulate query params
  const [name, setName] = useState('');
  const [location, setLocation] = useState('');

  // Read query params from the URL and update the states
  useEffect(() => {
    const nameParam = searchParams.get('name');
    const locationParam = searchParams.get('location');
    
    if (nameParam) setName(nameParam);
    if (locationParam) setLocation(locationParam);
  }, [searchParams]); // Triggers when searchParams change

  // Function to update query params in the URL when state changes
  useEffect(() => {
    const params = {};
    if (name) params.name = name;
    if (location) params.location = location;

    setSearchParams(params);
  }, [name, location, setSearchParams]); // Triggers when name or location states change

  return {
      name,
      setName,
      location,
      setLocation,
}
};

export default SearchComponent;

See? Simple. Now your states are SHARABLE as a links.

useRef

States and props indeed trigger re-renders in React, which is their default behavior. But if you need a value that persists across renders without triggering a re-render, useRef comes to the rescue.

useRef is perfect for storing a mutable value that doesn’t need to cause a re-render when it changes. It’s commonly used for things like referencing DOM elements or storing values that don’t affect the visual rendering of a component. If you need a variable to persist across renders without affecting the rendering logic, useRef is the tool for the job. This is useful for cases like: -Storing form field values, -Tracking intervals or timeouts, -Keeping some sort of history of states.

Conclusion.

React is a super-rich ecosystem that truly shows its magic when you start thinking outside the box. When you begin combining multiple old-school techniques with React’s modern ways, you unlock real innovation. Hooks like useRef, for example, can be used in ways they weren’t originally intended for, allowing you to be super creative. useState is just the beginning, but with other tools, libraries, and even the browser’s own APIs, you can achieve amazing results. I hope I’ve demonstrated a few of those wonders here.

Now, you can pull on your glowing sneakers and green mohawk like a React senior from the top photo—you’ve made it, brogrammer!

Latest posts:

• How to Escape the Frontend Medior Void?

• Would you rather be feared or loved?

• Are you authrised, dear sir??

• Happy healthy software developer

Share on: