From c374a8c54f5b28619076351331636c1fa1edfb5d Mon Sep 17 00:00:00 2001 From: Valeriy Komlev Date: Wed, 27 May 2026 12:47:50 +0200 Subject: [PATCH 1/7] docs: adding react extra questions --- public/templates/react.json | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/public/templates/react.json b/public/templates/react.json index f3d3990..cc32e9e 100644 --- a/public/templates/react.json +++ b/public/templates/react.json @@ -123,6 +123,18 @@ "text": "Error Boundaries", "score": 2, "extra": false + }, + { + "id": "routing", + "text": "Routing in React", + "score": 2, + "extra": false + }, + { + "id": "reactCompiler", + "text": "React Compiler", + "score": 3, + "extra": true } ] }, @@ -271,6 +283,12 @@ "score": 3, "extra": true }, + { + "id": "reactDevTools", + "text": "React DevTools", + "score": 1, + "extra": true + }, { "id": "ai", "text": "AI", "score": 2, "extra": true }, { "id": "cicd", @@ -297,6 +315,13 @@ "score": 2, "extra": true }, + { "id": "isr", "text": "ISR (Next.js)", "score": 1, "extra": true }, + { + "id": "nextJsRouting", + "text": "Routing in Next.js (app, pages)", + "score": 2, + "extra": true + }, { "id": "otherFrameworks", "text": "Other frameworks (Astro, Tanstack, Gatsby)", From 3fa9a48b5f5cf5f3fcd54e36e2da1a3f7d3a8e9c Mon Sep 17 00:00:00 2001 From: Valeriy Komlev Date: Wed, 27 May 2026 13:46:04 +0200 Subject: [PATCH 2/7] feat: adding outline functionality --- public/templates/react.json | 82 +- public/templates/react_outline.json | 1588 +++++++++++++++++ scripts/generate-templates.js | 3 +- src/components/00-Atoms/Icons/InfoIcon.tsx | 16 + .../01-Molecules/SectionCard/SectionCard.tsx | 59 +- .../ChecklistGrid/ChecklistGrid.tsx | 8 +- .../InterviewSectionCard.tsx | 13 +- .../OutlineDrawer/OutlineDrawer.tsx | 119 ++ .../TemplateViewPage/TemplateViewPage.tsx | 18 +- src/hooks/useOutline.ts | 36 + src/index.css | 14 + src/types.ts | 32 + 12 files changed, 1947 insertions(+), 41 deletions(-) create mode 100644 public/templates/react_outline.json create mode 100644 src/components/00-Atoms/Icons/InfoIcon.tsx create mode 100644 src/components/02-Organisms/OutlineDrawer/OutlineDrawer.tsx create mode 100644 src/hooks/useOutline.ts diff --git a/public/templates/react.json b/public/templates/react.json index cc32e9e..ce41df2 100644 --- a/public/templates/react.json +++ b/public/templates/react.json @@ -6,7 +6,7 @@ "name": "React", "description": "React developer checklist", "createdAt": "2025-09-21T13:02:32.480Z", - "updatedAt": "2025-09-21T13:02:32.480Z", + "updatedAt": "2026-05-27T00:00:00.000Z", "sections": [ { "id": "general", @@ -30,6 +30,36 @@ "text": "Keys in lists", "score": 1, "extra": false + }, + { + "id": "syntheticEvents", + "text": "Synthetic Events", + "score": 1, + "extra": false + }, + { + "id": "fragments", + "text": "Fragments", + "score": 1, + "extra": false + }, + { + "id": "controlledVsUncontrolled", + "text": "Controlled vs Uncontrolled Components", + "score": 2, + "extra": false + }, + { + "id": "lifecycle", + "text": "Component Lifecycle", + "score": 2, + "extra": false + }, + { + "id": "reconciliation", + "text": "Reconciliation & Fiber Architecture", + "score": 3, + "extra": true } ] }, @@ -77,7 +107,25 @@ "score": 3, "extra": true }, - { "id": "useId", "text": "useId", "score": 1, "extra": true } + { "id": "useId", "text": "useId", "score": 1, "extra": true }, + { + "id": "customHooks", + "text": "Custom Hooks", + "score": 2, + "extra": false + }, + { + "id": "useDeferredValue", + "text": "useDeferredValue", + "score": 3, + "extra": true + }, + { + "id": "useImperativeHandle", + "text": "useImperativeHandle", + "score": 2, + "extra": true + } ] }, { @@ -135,6 +183,24 @@ "text": "React Compiler", "score": 3, "extra": true + }, + { + "id": "forwardRef", + "text": "forwardRef", + "score": 2, + "extra": false + }, + { + "id": "suspense", + "text": "Suspense & React.lazy", + "score": 2, + "extra": false + }, + { + "id": "compoundComponents", + "text": "Compound Components", + "score": 3, + "extra": true } ] }, @@ -179,6 +245,12 @@ "text": "Sass/Less", "score": 1, "extra": true + }, + { + "id": "cssReset", + "text": "CSS Reset", + "score": 1, + "extra": false } ] }, @@ -235,9 +307,9 @@ "extra": true }, { - "id": "react", - "text": "Reset Styles", - "score": 1, + "id": "reactProfiler", + "text": "React Profiler", + "score": 2, "extra": true } ] diff --git a/public/templates/react_outline.json b/public/templates/react_outline.json new file mode 100644 index 0000000..2bf176c --- /dev/null +++ b/public/templates/react_outline.json @@ -0,0 +1,1588 @@ +{ + "id": "react_outline", + "checklistId": "react", + "version": "1.0.0", + "name": "React Developer Training Outline", + "description": "Study guide and key concepts for each topic in the React developer checklist", + "createdAt": "2026-05-27T00:00:00.000Z", + "updatedAt": "2026-05-27T00:00:00.000Z", + "sections": [ + { + "id": "general", + "title": "General", + "topics": [ + { + "id": "jsx", + "title": "JSX", + "summary": "JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside JS files. Babel/SWC compiles it to `React.createElement()` calls at build time.", + "keyPoints": [ + "Compiles to React.createElement(type, props, ...children)", + "Must have a single root element — use Fragments to avoid extra DOM nodes", + "HTML attributes are camelCase: className, htmlFor, onClick", + "JavaScript expressions go inside {curly braces}", + "Self-closing tags must be closed: ,
", + "Conditional rendering: ternary ({cond ? : }) or short-circuit ({cond && })", + "JSX is not HTML — style takes an object, not a string" + ], + "resources": [ + { + "title": "Writing Markup with JSX", + "url": "https://react.dev/learn/writing-markup-with-jsx" + }, + { + "title": "JavaScript in JSX with Curly Braces", + "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces" + } + ] + }, + { + "id": "virtualDom", + "title": "Virtual DOM", + "summary": "The Virtual DOM is an in-memory JavaScript representation of the real DOM. React uses it to batch and minimize actual DOM updates by diffing the previous and next virtual trees.", + "keyPoints": [ + "React keeps a virtual tree in memory mirroring the real DOM", + "On state/prop change, a new virtual tree is created and compared (diffing)", + "Only changed nodes are applied to the real DOM (patching/reconciliation)", + "Diffing runs in O(n) using heuristics: same element type = update, different type = replace whole subtree", + "Keys help React match list items across renders", + "React Fiber is the internal engine that makes reconciliation interruptible" + ], + "resources": [ + { + "title": "Preserving and Resetting State", + "url": "https://react.dev/learn/preserving-and-resetting-state" + }, + { + "title": "React Fiber Architecture (community)", + "url": "https://github.com/acdlite/react-fiber-architecture" + } + ] + }, + { + "id": "oneWayDataFlow", + "title": "One-way data flow", + "summary": "Data in React flows in a single direction — from parent to child via props. Children communicate upward by calling callback functions passed as props.", + "keyPoints": [ + "Props flow down: parent → child", + "Events flow up: child calls a function prop to notify parent", + "Makes data flow predictable and easy to trace and debug", + "Contrast with two-way binding (Angular ngModel, Vue v-model)", + "Lifting state up: move shared state to the closest common ancestor", + "Prop drilling: passing props through many layers — solved by Context or a state manager" + ], + "resources": [ + { + "title": "Sharing State Between Components", + "url": "https://react.dev/learn/sharing-state-between-components" + }, + { + "title": "Thinking in React", + "url": "https://react.dev/learn/thinking-in-react" + } + ] + }, + { + "id": "keysInLists", + "title": "Keys in lists", + "summary": "Keys are stable string/number identifiers that help React match rendered list items to their previous versions across re-renders, enabling efficient updates.", + "keyPoints": [ + "Keys must be unique among siblings (not globally unique)", + "Use stable IDs from your data source — not array index if the list can reorder", + "Using index as key causes bugs with stateful items, animations, and focus", + "Keys are not passed as props — use a separate prop if the child needs the ID", + "Missing keys = React warns and falls back to less efficient reconciliation", + "Keys should be on the outermost element returned in a .map() call" + ], + "resources": [ + { + "title": "Rendering Lists", + "url": "https://react.dev/learn/rendering-lists" + } + ] + }, + { + "id": "syntheticEvents", + "title": "Synthetic Events", + "summary": "React wraps native browser events in a SyntheticEvent object that normalizes behavior across browsers. Since React 17, events are attached to the root container rather than document.", + "keyPoints": [ + "SyntheticEvent wraps the native event with a consistent cross-browser API", + "React uses event delegation — one listener at the root, not per element", + "Access the native event via e.nativeEvent", + "Pre-React 17: event pooling (events reused — had to call e.persist()); removed in v17+", + "Stopping propagation: e.stopPropagation(), e.preventDefault()", + "All standard DOM events are supported with the on prefix: onClick, onChange, onKeyDown, onSubmit" + ], + "resources": [ + { + "title": "Responding to Events", + "url": "https://react.dev/learn/responding-to-events" + }, + { + "title": "React Event Object Reference", + "url": "https://react.dev/reference/react-dom/components/common#react-event-object" + } + ] + }, + { + "id": "fragments", + "title": "Fragments", + "summary": "Fragments let you group multiple children elements without adding extra nodes to the DOM — useful when a component must return multiple siblings.", + "keyPoints": [ + "Shorthand: <> — cannot accept props", + "Full form: — supports the key prop when mapping", + "Prevents unnecessary wrapper
nodes that break CSS (flex/grid children, table rows)", + "Particularly important for / and
/
/
structures", + "Zero cost — fragments produce no DOM output" + ], + "resources": [ + { + "title": "Fragment Reference", + "url": "https://react.dev/reference/react/Fragment" + } + ] + }, + { + "id": "controlledVsUncontrolled", + "title": "Controlled vs Uncontrolled Components", + "summary": "Controlled components have their form value driven by React state. Uncontrolled components let the DOM hold the value, accessed imperatively via refs.", + "keyPoints": [ + "Controlled: value prop + onChange handler — React is the single source of truth", + "Uncontrolled: defaultValue (not value) + useRef to read imperatively", + "Controlled gives real-time access: instant validation, conditional rendering, formatting", + "Uncontrolled is simpler for file inputs ( is always uncontrolled)", + "React Hook Form uses uncontrolled inputs for performance (fewer re-renders)", + "Never switch between controlled/uncontrolled for the same input — causes warnings" + ], + "resources": [ + { + "title": "Controlled and Uncontrolled Inputs", + "url": "https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable" + }, + { + "title": "React Hook Form", + "url": "https://react-hook-form.com/" + } + ] + }, + { + "id": "lifecycle", + "title": "Component Lifecycle", + "summary": "React components go through mount, update, and unmount phases. Function components use useEffect to handle all lifecycle phases; class components have explicit lifecycle methods.", + "keyPoints": [ + "Mount: component renders and is inserted into the DOM", + "Update: re-renders when state or props change", + "Unmount: component is removed from the DOM — run cleanup", + "useEffect(() => { setup; return cleanup; }, [deps]) covers all three phases", + "No deps array = runs after every render", + "[] = runs once after mount, cleanup on unmount", + "[dep] = runs when dep changes; cleanup before next run", + "Class equivalents: componentDidMount, componentDidUpdate, componentWillUnmount", + "getDerivedStateFromProps and getSnapshotBeforeUpdate for advanced cases" + ], + "resources": [ + { + "title": "Lifecycle of Reactive Effects", + "url": "https://react.dev/learn/lifecycle-of-reactive-effects" + }, + { + "title": "Synchronizing with Effects", + "url": "https://react.dev/learn/synchronizing-with-effects" + } + ] + }, + { + "id": "reconciliation", + "title": "Reconciliation & Fiber Architecture", + "summary": "Reconciliation is React's diffing algorithm that computes the minimal set of DOM changes. Fiber is React's internal reimplementation of the reconciler enabling incremental, interruptible rendering.", + "keyPoints": [ + "React diffs element type first: different type = full subtree replacement", + "Same type = update props in place, recurse into children", + "List diffing uses keys to map old children to new children in O(n)", + "Fiber: each component instance is a 'fiber' — a unit of work with priority", + "Fiber tree: work-in-progress tree built alongside the current tree (double buffering)", + "Concurrent Mode: Fiber allows React to pause/resume/abort renders", + "Priority lanes: user input (high) preempts background data updates (low)", + "Commit phase: once a complete work-in-progress tree is ready, React flushes changes synchronously to the DOM" + ], + "resources": [ + { + "title": "What is Concurrent React?", + "url": "https://react.dev/blog/2022/03/29/react-v18#what-is-concurrent-react" + }, + { + "title": "React Fiber Architecture (community deep-dive)", + "url": "https://github.com/acdlite/react-fiber-architecture" + } + ] + } + ] + }, + { + "id": "hooks", + "title": "Hooks", + "topics": [ + { + "id": "useState", + "title": "useState", + "summary": "useState adds local, reactive state to function components. It returns a current value and a setter; calling the setter schedules a re-render with the new value.", + "keyPoints": [ + "const [state, setState] = useState(initialValue)", + "Initial value can be a lazy initializer function: useState(() => expensiveCompute())", + "Setter can take a value or an updater function: setState(prev => prev + 1)", + "Always use the functional form when new state depends on old state", + "State updates are asynchronous — the new value is available on the next render", + "React 18: automatic batching groups multiple setState calls in async code too", + "Each useState call is independent; split state by concern, not into one big object" + ], + "resources": [ + { + "title": "useState Reference", + "url": "https://react.dev/reference/react/useState" + }, + { + "title": "State: A Component's Memory", + "url": "https://react.dev/learn/state-a-components-memory" + } + ] + }, + { + "id": "useReducer", + "title": "useReducer", + "summary": "useReducer manages complex state with a pure reducer function and dispatched actions — an alternative to useState when state transitions involve multiple sub-values or complex logic.", + "keyPoints": [ + "const [state, dispatch] = useReducer(reducer, initialState)", + "Reducer signature: (state, action) => newState — must be pure", + "Actions typically follow { type, payload } convention (like Redux)", + "Prefer over useState when: next state depends on multiple fields, or logic is complex/shared", + "dispatch has a stable reference — safe to pass down without useCallback", + "Can pass dispatch instead of multiple setter callbacks to child components", + "Initialize lazily: useReducer(reducer, arg, initFn) — initFn(arg) called once" + ], + "resources": [ + { + "title": "useReducer Reference", + "url": "https://react.dev/reference/react/useReducer" + }, + { + "title": "Extracting State Logic into a Reducer", + "url": "https://react.dev/learn/extracting-state-logic-into-a-reducer" + } + ] + }, + { + "id": "useEffect", + "title": "useEffect", + "summary": "useEffect synchronizes a component with an external system — API calls, subscriptions, DOM manipulation — running after render and optionally cleaning up before the next run or unmount.", + "keyPoints": [ + "Runs after the browser has painted — not synchronous with render", + "Dependency array controls when it re-runs: [] = once, [dep] = on dep change, omitted = every render", + "Return a cleanup function to cancel subscriptions, timers, abort controllers", + "In React 18 StrictMode (dev only): effects run twice to catch missing cleanups", + "Do NOT use to sync two pieces of React state — use derived state or useMemo instead", + "Common pitfalls: missing dependencies (stale closure), infinite loops (setting state without guard), forgetting cleanup" + ], + "resources": [ + { + "title": "useEffect Reference", + "url": "https://react.dev/reference/react/useEffect" + }, + { + "title": "You Might Not Need an Effect", + "url": "https://react.dev/learn/you-might-not-need-an-effect" + } + ] + }, + { + "id": "useLayoutEffect", + "title": "useLayoutEffect", + "summary": "useLayoutEffect fires synchronously after all DOM mutations but before the browser paints — use it to read layout metrics or imperatively fix the DOM before the user sees it.", + "keyPoints": [ + "Identical signature to useEffect", + "Runs synchronously between React's DOM mutations and the browser paint", + "Blocks paint — keep it fast; avoid async operations", + "Use cases: measuring DOM element dimensions, syncing scroll position, tooltip/popover positioning", + "Does NOT run on the server (use useEffect or suppress the warning for SSR-safe code)", + "Prefer useEffect — only reach for useLayoutEffect when you see visual flicker" + ], + "resources": [ + { + "title": "useLayoutEffect Reference", + "url": "https://react.dev/reference/react/useLayoutEffect" + } + ] + }, + { + "id": "useMemo", + "title": "useMemo", + "summary": "useMemo memoizes the result of an expensive calculation, recomputing only when its dependencies change. It also provides referential stability for objects and arrays.", + "keyPoints": [ + "const value = useMemo(() => expensiveCalc(a, b), [a, b])", + "Does NOT prevent re-renders by itself — pair with React.memo on the child for that", + "Primary uses: (1) skip expensive recalculations, (2) stable object/array references for deps", + "Memoization has overhead — profile before adding, don't apply everywhere", + "The React Compiler can handle most useMemo automatically in the future", + "Return value must be deterministic given the same deps" + ], + "resources": [ + { + "title": "useMemo Reference", + "url": "https://react.dev/reference/react/useMemo" + } + ] + }, + { + "id": "useCallback", + "title": "useCallback", + "summary": "useCallback returns a memoized function reference that only changes when its dependencies change, preventing child components from re-rendering due to new function references.", + "keyPoints": [ + "const fn = useCallback(() => doSomething(a), [a])", + "Equivalent to useMemo(() => fn, deps) — syntactic sugar for functions", + "Needed when passing callbacks to children wrapped in React.memo", + "Needed when a function is listed as a useEffect dependency", + "Without useCallback, a new function reference is created on every parent render", + "Premature optimization — profile first; the React Compiler will automate this" + ], + "resources": [ + { + "title": "useCallback Reference", + "url": "https://react.dev/reference/react/useCallback" + } + ] + }, + { + "id": "useContext", + "title": "useContext", + "summary": "useContext reads and subscribes to a React Context, letting components consume a shared value without threading props through every level of the tree.", + "keyPoints": [ + "const value = useContext(MyContext) — returns the nearest Provider's value", + "Any value change in the Provider triggers re-render of ALL consumers (no built-in selector)", + "Split contexts by update frequency to limit unnecessary re-renders", + "Wrap the provided value in useMemo to keep the reference stable", + "Context is not a replacement for a global state manager in large apps", + "Good for: theme, auth user, locale — low-frequency, broadly needed data" + ], + "resources": [ + { + "title": "useContext Reference", + "url": "https://react.dev/reference/react/useContext" + }, + { + "title": "Passing Data Deeply with Context", + "url": "https://react.dev/learn/passing-data-deeply-with-context" + } + ] + }, + { + "id": "useRef", + "title": "useRef", + "summary": "useRef returns a mutable object { current: value } that persists across renders without triggering re-renders. Used for DOM references and storing mutable values.", + "keyPoints": [ + "const ref = useRef(initialValue) — ref.current is the mutable container", + "Mutating ref.current does NOT cause a re-render", + "DOM refs: → myRef.current is the DOM node", + "Mutable storage: interval IDs, previous values, animation frames", + "Callback ref: ref={node => { ... }} for setup/teardown on mount/unmount", + "Do not read/write ref.current during render — use state for that" + ], + "resources": [ + { + "title": "useRef Reference", + "url": "https://react.dev/reference/react/useRef" + }, + { + "title": "Referencing Values with Refs", + "url": "https://react.dev/learn/referencing-values-with-refs" + } + ] + }, + { + "id": "useSyncExternalStore", + "title": "useSyncExternalStore", + "summary": "useSyncExternalStore is the official API for subscribing to external stores (Redux, Zustand, browser APIs) in a way that is safe for concurrent rendering, preventing tearing.", + "keyPoints": [ + "const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)", + "subscribe: function that registers a listener and returns an unsubscribe function", + "getSnapshot: synchronously returns the current store value — must be pure and stable", + "Prevents 'tearing' where different components read different values during a concurrent render", + "Used internally by Redux, Zustand, and other major libraries", + "getServerSnapshot: optional, for SSR to avoid hydration mismatches" + ], + "resources": [ + { + "title": "useSyncExternalStore Reference", + "url": "https://react.dev/reference/react/useSyncExternalStore" + } + ] + }, + { + "id": "useTransition", + "title": "useTransition", + "summary": "useTransition marks state updates as non-urgent transitions, allowing React to keep the UI responsive to urgent updates (user input) while processing the slower update in the background.", + "keyPoints": [ + "const [isPending, startTransition] = useTransition()", + "Wrap low-priority state updates: startTransition(() => setTab(next))", + "React may interrupt and restart the transition if a higher-priority update comes in", + "isPending is true while the transition is in progress — show spinners/skeletons", + "Different from debouncing: React still processes the update, just at lower priority", + "Use cases: tab switching, large list filtering, any heavy re-render triggered by user input" + ], + "resources": [ + { + "title": "useTransition Reference", + "url": "https://react.dev/reference/react/useTransition" + } + ] + }, + { + "id": "useId", + "title": "useId", + "summary": "useId generates a unique, stable ID that is consistent between server and client renders — useful for linking accessibility attributes without hydration mismatches.", + "keyPoints": [ + "const id = useId() — generates a string like ':r0:'", + "SSR-safe: same ID generated on server and client (no hydration mismatch)", + "Do NOT use as list keys — use data IDs for that", + "Common pattern: link label to input for a11y —