Application State Management
By Syncfusion®, Inc. · Last updated
Shared state, state ownership, lifting state up, managing shared state, keeping parent and child in sync, where to place state, local vs global state, and choosing an approach.
Introduction to Shared State
Shared state is state that more than one component needs. For example, the number of books in the cart is shown in the header and on the cart page.
If each component keeps its own copy, the copies can show different numbers. To keep them the same, you keep one copy and share it.
Real-World Example
In a bookshop app, the header shows the cart count, the book page adds items, and the checkout page shows the total. All three read the same cart.
The cart is kept in one place: a CartProvider with useReducer. Each component sends actions such as { type: "add", book }, and every part of the page shows the same cart.
Left: two siblings each keep their own count, so they disagree. Right: the parent keeps one count and passes it to both, so they agree Each child has its own state
App
Header count = 2
CartPage count = 5 Different numbers The parent has the state
App count = 5
5
5
Header shows 5
CartPage shows 5 Same number
When two components must show the same data, keep one copy of it in their parent.
If two components must always show the same data, they must not each keep their own copy. Keep one copy, in one place.
State Ownership
Every piece of state has an owner: the one component that creates it with useState. Only the owner can change it.
Other components get the state from the owner:
- To read it, they receive it as a prop.
- To change it, they receive a function from the owner and call it.
This keeps one clear rule: there is one place where the data lives, and one place where it changes.
The lab below shows what goes wrong without a shared owner. Each component owns its own count.
Click the button a few times. The button's number goes up, but the badge stays at 0. Each component owns its own count, so they do not know about each other.
Lifting State Up
Lifting state up means moving the state from a child up to its parent. The parent becomes the owner. Then it passes the state down to every child that needs it.
There are three steps:
- Move the
useStateline from the child up to the parent. - Pass the value down to the children as a prop.
- Pass a function down to the child that changes it.
Lifting state up: the state moves from a child up to the parent
App (parent) new home of the state
LikeButton
LikeCount
likes
The likes state moves up from a child to the parent. Now both children can use it.
Click the button. Now the badge changes too. App owns count. CartBadge only shows it, and AddButton only asks App to change it.
Neither child has useState any more. They are now simple components that get everything from props.
Shared State Management
Shared state management means deciding how shared state is stored, read and changed. When many children use the same state, keep these points in mind:
- One owner — Only one component has the
useStatefor it. - Read with props — Children receive the value as a prop.
- Change with functions — Children receive functions such as
onAddoronRemove. They never change the value themselves. - Clear names — Name function props after the action:
onAdd,onRemove,onClear.
App owns the cart. The heading, BookList and CartSummary all show the same cart, because there is only one.
Parent-Child State Synchronization
Synchronization means keeping two things the same. A parent and a child stay in sync when:
- the parent sends the current value down as a prop, and
- the child sends changes up by calling a function prop.
This is often used for inputs. The parent owns the text, and the child shows the input box.
Parent and child stay in sync: data goes down as props, changes go up through a function prop
App search = "hab"
SearchBox <input />
value (prop) onSearch (function)
Data flows down as props. Changes flow up when the child calls a function from the parent.
Type in the box. The list filters as you type. Now click Clear. The parent sets search to "", and the box inside the child becomes empty too. Parent and child always show the same text.
Look at this line in App:
<SearchBox value={search} onSearch={setSearch} />
value={search} sends the text down. onSearch={setSearch} gives the child a way to change it.
State Placement Strategy
Where should a piece of state live? Follow these steps:
- List every component that reads or changes the state.
- Find their closest shared parent in the component tree.
- Put the state there. If only one component needs it, keep it in that component.
State placement: find the closest parent shared by every component that needs the state
App
Shop cart lives here
Footer does not need it
Header needs cart
BookList needs cart
Header and BookList need the cart. Their closest shared parent is Shop, so the cart state goes there.
Do not put the state higher than it needs to be. If you put everything in App, then every change re-renders the whole app, and App becomes very long.
The lab below places each piece of state in the right spot:
isOpenis used only byMenu, so it stays local insideMenu.cartis used byHeaderandBookList, so it lives inShop, their closest shared parent.
Open the menu and add books. Opening the menu does not touch the cart, and adding a book does not touch the menu. Each state lives only where it is needed.
Keep state as low as possible, but as high as needed. Start in the component that uses it. Lift it up only when another component needs it too.
Local State Compared with Global State
- Local state belongs to one component, or to a small group with a shared parent. Examples: the text in a search box, whether a menu is open.
- Global state is used by many components all over the app. Examples: the logged-in user, the theme, the language, the cart.
Local state lives inside one component. Global state is shared with many components across the app Local state
SearchBox
text = "hab" used by one component Global state
user = Asha shared by many
Header
Cart
Profile
Keep state local when only one component needs it. Make it global only when many parts of the app need it.
| Local state | Global state | |
|---|---|---|
| Who uses it | One component, or a small group | Many components across the app |
| Where it lives | Inside the component, or its parent | Near the top of the app |
| How it is shared | Props | Context (next lesson), or a state library |
| Examples | Input text, open/closed, selected tab | Logged-in user, theme, language, cart |
Most state in an app is local. Only a few things are truly global.
Choosing a State Management Approach
Pick the simplest approach that works. Move to the next one only when you have a real problem.
| Situation | Approach |
|---|---|
| Only one component uses the state | useState in that component |
| A few nearby components need it | Lift it up to their shared parent, and pass props |
| The state has many kinds of changes | useReducer in the owner |
| Many components far apart need it | Context (next lesson) |
| A very big app with lots of shared data | A state library, such as Redux Toolkit or Zustand |
Most apps need only useState, lifting state up, and a little context. Reach for a state library only when the app is large and these are not enough.
Common mistakes
| Mistake | What you see | Fix |
|---|---|---|
| Two components each keep their own copy of the same data | They show different values | Lift the state to their shared parent |
| A child changes a prop directly | Error, or the change is lost | Call a function prop from the parent |
Putting all state in App | App is huge, and every change re-renders everything | Keep state in the lowest shared parent |
| Copying a prop into the child's own state | The child stops updating when the parent changes | Use the prop directly |
Passing setCount(count + 1) instead of a function | It runs while rendering, and loops | Pass () => setCount(count + 1) |
| Using global state for everything | The code is hard to follow | Keep most state local |
Check Yourself
Exercises
What to Remember
- When two components need the same data, keep one copy in their closest shared parent. This is lifting state up.
- The owner passes the value down as props, and passes functions down so children can ask for changes.
- Keep state as low as possible. Most state is local. Use context only for truly global data.
Next: Context API