React Derived State
Avoid a synchronization problem by storing the user’s choice and deriving the visible result.
How it works
Duplicated state often creates bugs that look like missed effects. If a list and a search term already exist, the matching list can usually be calculated during rendering. There is no need for a second state cell and an effect that copies the result into it. The example filters a small in-memory inventory as the user types. Expensive derivations may later justify memoization, but correctness comes first.
Run the code
Use a separate empty lab folder with Node 22.12+ in the 22 series. Save the files below using their displayed paths; browsers may download only the basename, so create src, public or tests folders as listed. The pinned project uses React and React DOM 19.3.1 with Vite 7.3.1. Run npm install, then npm run dev and open the local address Vite prints. React examples do not run in Bhylu’s current playground.
No Apache, MySQL or change to Bhylu’s server configuration is needed. These are local teaching projects, not a publishing package. Keep generated dependencies and lockfiles in your own lab. Review the project setup.
Example
import React, { StrictMode, useState } from 'react';
import { createRoot } from 'react-dom/client';
import './style.css';
const names = ['Market basket', 'Folding stool', 'Desk lamp'];
function App() {
const [query, setQuery] = useState('');
const matches = names.filter((name) =>
name.toLowerCase().includes(query.toLowerCase()),
);
return (
<main>
<h1>Neighbourhood lending desk</h1>
<label>
Find an item
<input value={query} onChange={(event) => setQuery(event.target.value)} />
</label>
<ul>
{matches.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
<output>{matches.length} matches</output>
</main>
);
}
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
);
Expected result
Typing basket leaves one result and the matching count stays consistent.
query is state because the user changes it. matches is a derivation of query and the fixed inventory. The same render calculates the rows and count, so they cannot disagree because an effect has not run yet. If the inventory comes from a request, store its received data and request status separately; do not confuse network state with a pure filtering calculation.
For API contracts and version differences, use React’s official documentation.