Rendering lists in React is just mapping over an array to produce elements, but each element needs a stable key prop. Keys give every list item a stable identity so React can efficiently track, reorder, add, or remove items during reconciliation. Without proper keys, React may re-render entire lists or wrongly carry component state across items. The best key is a unique, stable identifier such as a database ID. The array index should be avoided when the list can be reordered, filtered, or modified, because index-based keys cause incorrect state mapping and subtle rendering bugs.
Events in React look like HTML but differ in important details. Event handlers are named in camelCase (onClick, onChange) and are passed function references rather than strings. A subtle but common mistake is writing onClick={handleClick()}, which invokes the function during render instead of when the user clicks — the correct form is onClick={handleClick}. React wraps native events in a SyntheticEvent, a cross-browser abstraction that exposes the same interface (preventDefault, stopPropagation, and so on) so handlers behave consistently across browsers.
Performance optimization in React is mostly about preventing unnecessary work. React.memo is a higher-order component that skips re-rendering a functional component when its props have not changed (using a shallow comparison). Combined with useMemo for computed values and useCallback for stable function identities, it lets you keep child components from re-rendering when their inputs have not actually changed. Lazy loading is another lever: React.lazy(() => import('./MyComp')) splits a component into its own bundle that is fetched on demand, reducing the initial download size. Pairing it with <Suspense fallback={<Loading />}> lets you display a fallback UI while the chunk loads. For very long lists, virtualization libraries such as react-window render only the rows visible in the viewport, keeping scroll performance smooth even with thousands of items.