Bonus: React State Anti‑Patterns (SPFx)

Bonus: React State Anti‑Patterns (SPFx)

Common pitfalls that slow down SPFx apps or cause subtle bugs, with practical fixes.

Duplicate derived state

Avoid storing values that can be derived from existing state.

const [items, setItems] = React.useState<string[]>([]);
const filtered = React.useMemo(() => items.filter(i => i.includes(q)), [items, q]);

Mutable updates

Never mutate arrays/objects in place; create new references.

setItems(prev => prev.map(i => (i === old ? next : i)));
setUser(prev => ({ ...prev, name: nextName }));

Index keys in lists

Using indexes as keys breaks identity on reorders. Use stable IDs.

{items.map(item => <Row key={item.id} item={item} />)}

Inline objects/functions causing re-renders

Stabilize props with useMemo/useCallback when rendering large lists.

const columns = React.useMemo(() => [{ key: 'name', name: 'Name' }], []);
const onSelect = React.useCallback((id: string) => setSelected(id), []);

Overloaded Context

Huge context values cause widespread re-renders. Split contexts or use selectors.

const ThemeContext = React.createContext<string>('default');
const UserContext = React.createContext<{ id: string } | null>(null);

setState after unmount

Cancel async work on unmount or property changes.

React.useEffect(() => {
  const ac = new AbortController();
  (async () => {
    const res = await fetch(url, { signal: ac.signal });
    // setState safely
  })();
  return () => ac.abort();
}, [url]);

SPFx notes

  • Property pane changes: debounce heavy derivations and network calls.
  • Keep SPFx Context in containers; presentational components should remain pure.
  • Virtualize large lists with Fluent UI List/DetailsList.

See also