Components and JSX
Keep rendering pure
Make component output depend only on props, state, and context without changing outside values during render.
Rendering must be a calculation, not an operation on the outside world.
Given the same props, state, and context, a component should return the same JSX. That lets React pause, restart, or repeat rendering safely.
This component is impure:
let nextId = 0
function Task() {
nextId += 1
return <p>Task {nextId}</p>
}
Render it twice and you get Task 1, then Task 2. Two separate instances also share the same counter, so they affect each other.
Do not mutate props, write storage, start timers, send requests, or change the DOM while rendering.
Put work where its cause belongs:
- A click-caused request belongs in the click handler.
- A value derived from props belongs in the render calculation.
- Synchronization with an external system belongs in an Effect.
Local mutation is fine when the value was created during this render:
const rows = []
for (const task of tasks) {
rows.push(<li key={task.id}>{task.title}</li>)
}
The new rows array does not affect an earlier render or another component.
Strict Mode intentionally repeats some development work to reveal impurities. If a repeated render creates duplicate data or requests, fix where that side effect occurs rather than disabling the check.
A common mistake is fetching data directly in the component body. That looks like rendering, but it changes the outside world every time React runs the function. Move the fetch into an Effect or a data loader instead.
Mutating props is the same class of bug. Treat props as read-only inputs to the render calculation.
Add a console.log to a component and watch renders happen. Then verify that calling the component function again does not change application data outside it.
Lesson completed