Rules Hub
Coding Rules Library
Rule priority, scope & exceptions
Use this to align rules with the senior-level structure (P0/P1/P2, scope, exceptions/tradeoffs).
Memoize stable callback props with useCallback
When passing non-trivial handlers to hooks or child components, extract them and wrap them in useCallback so they are not recreated on every render.
Bad example
| 1 | const { fetchPortfolioInstruments } = useFetchPortfolioInstruments({ |
| 2 | onPortfolioDetails: details => { |
| 3 | setSelectedPortfolio(prevState => { |
| 4 | if (!prevState) { |
| 5 | return details; |
| 6 | } |
| 7 |
|
| 8 | return { |
| 9 | ...prevState, |
| 10 | ...details, |
| 11 | }; |
| 12 | }); |
| 13 | }, |
| 14 | }); |
Explanation (EN)
The callback is recreated on every render and hides reusable logic inside an inline prop. That makes dependency behavior harder to reason about and can trigger unnecessary downstream updates.
Objašnjenje (HR)
Callback se ponovno kreira pri svakom renderu i skriva ponovljivo ponasanje unutar inline propa. To otežava pracenje dependency ponašanja i moze uzrokovati nepotrebne downstream updateove.
Good example
| 1 | const handlePortfolioDetails = useCallback( |
| 2 | (details: Pick<PortfolioDetailedResponse, 'id' | 'name' | 'order' | 'showBenchmark' | 'includeDividends'>) => { |
| 3 | setSelectedPortfolio(prevState => { |
| 4 | if (!prevState) return details; |
| 5 | return { ...prevState, ...details }; |
| 6 | }); |
| 7 | }, |
| 8 | [setSelectedPortfolio] |
| 9 | ); |
| 10 |
|
| 11 | const { fetchPortfolioInstruments } = useFetchPortfolioInstruments({ |
| 12 | onPortfolioDetails: handlePortfolioDetails, |
| 13 | }); |
Explanation (EN)
The handler has a stable identity, the merge logic is named and reusable, and hook dependencies are easier to understand and maintain.
Objašnjenje (HR)
Handler ima stabilan identitet, merge logika je imenovana i ponovno iskoristiva, a hook dependencies su laksi za razumjeti i odrzavati.
Notes (EN)
Prefer this when the callback contains merge logic, side effects, or is passed into custom hooks. Tiny one-line DOM event handlers inside JSX do not always need extraction.
Bilješke (HR)
Preferiraj ovo kada callback sadrzi merge logiku, side effecte ili se prosljeduje u custom hookove. Sitni one-line DOM event handleri u JSX-u ne trebaju uvijek izdvajanje.
Exceptions / Tradeoffs (EN)
Inline callbacks are acceptable when they are trivial, local to a leaf component, and not passed into memoized/custom-hook APIs.
Iznimke / Tradeoffi (HR)
Inline callbacki su prihvatljivi kada su trivijalni, lokalni za leaf komponentu i ne prosljeduju se memoized/custom-hook API-jima.