{"id":"l-rf-4-4","courseId":"react-fundamentals","lang":"en","kind":"wrapup","summary":"Review what you can now build with React, extend the Watchlist with concrete challenges, and choose the next topics to learn in an order that builds on this course.","html":"<p>Eighteen lessons ago you had an empty folder. Now you have a deployed app built from small components, with state that lives in one place, derived values that can’t drift, a form with real validation, an Effect that persists data and cleans up after itself, a stylesheet you didn’t have to write by hand, and a URL. More importantly, you know <em>why</em> each of those decisions was made, which is what lets you make them again in a different app.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">What you can do now</h2>\n<p>Look back at the six promises on the course page and check each one against something you built:</p>\n<ul>\n<li><strong>Components, props and state</strong>: every part of the Watchlist, from <code dir=\"ltr\">MovieItem</code> to <code dir=\"ltr\">App</code>.</li>\n<li><strong>A React 19 and Vite workflow</strong>: <code dir=\"ltr\">npm create vite@latest</code>, the dev server, <code dir=\"ltr\">npm run build</code>.</li>\n<li><strong>Events, forms and controlled inputs</strong>: the add-movie form, with trimming, disabling and clearing.</li>\n<li><strong>Effects the right way</strong>: the tab title and localStorage, and all the places you <em>didn’t</em> use one.</li>\n<li><strong>Composing screens from small pieces</strong>: <code dir=\"ltr\">Panel</code>, <code dir=\"ltr\">MovieList</code> and the rest, each with a few props and a clear job.</li>\n<li><strong>Shipping to production</strong>: a Vercel deployment with preview URLs for every branch.</li>\n</ul>\n<h2 id=\"sec-2\" tabindex=\"-1\">Make the Watchlist yours</h2>\n<p>The fastest way to make this stick is to keep building the same app, without a tutorial. Each of these uses only what you’ve learned:</p>\n<ol>\n<li><strong>Sort</strong>: a select for “Newest first” and “Title A–Z”. One new piece of state, one derived list.</li>\n<li><strong>Edit a title</strong>: double-click a title to turn it into an input; Enter saves, Escape cancels.</li>\n<li><strong>Search</strong>: a text field that filters by title as you type, combined with the status filter.</li>\n<li><strong>Undo remove</strong>: keep the last removed movie and show an “Undo” button for a few seconds. You’ll need a timer in an Effect, with cleanup.</li>\n<li><strong>Keyboard shortcut</strong>: press “/” to focus the add field, with a window listener in an Effect and a <code dir=\"ltr\">ref</code>.</li>\n</ol>\n<p>Push each feature on its own branch and check its preview URL before merging, exactly like a team would.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">What to learn next</h2>\n<p>An order that builds on this course:</p>\n<ol>\n<li><strong>TypeScript.</strong> Typing props and state catches a whole class of bugs before you run anything, and most React job listings expect it. Start a project with <code dir=\"ltr\">--template react-ts</code>, or convert the Watchlist file by file. The <a href=\"/courses/advanced-typescript\">Advanced TypeScript Patterns</a> course goes much further once you’re comfortable.</li>\n<li><strong>Testing.</strong> Vitest with React Testing Library lets you render a component, click it like a user and assert on the result. Your small components are already easy to test. See <a href=\"/courses/testing-javascript\">Testing JavaScript Apps</a>.</li>\n<li><strong>More Hooks.</strong> <code dir=\"ltr\">useRef</code> for DOM access and values that don’t trigger renders, <code dir=\"ltr\">useReducer</code> when update logic grows, and <code dir=\"ltr\">useContext</code> for data many components need. The React Compiler, an optional build step, handles most memoization, so learn <code dir=\"ltr\">useMemo</code> and <code dir=\"ltr\">memo</code> but don’t sprinkle them everywhere.</li>\n<li><strong>Data fetching.</strong> Real apps load data from servers. Fetching in an Effect works for simple cases if you handle race conditions; for anything more, use TanStack Query, which handles caching, loading and error states for you.</li>\n<li><strong>Routing and frameworks.</strong> For several pages, add React Router. For server rendering, data loading and React Server Components, use a framework such as Next.js or React Router’s framework mode, as the React docs recommend for new full-scale apps.</li>\n</ol>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">Tip</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Learn in your own project</span></p>\n<p>When you study a new tool, add it to the Watchlist instead of starting a tutorial project. You already understand every line of the app, so the only new thing is the tool itself.</p>\n</aside>\n<p>You came here to build interactive UIs with React. You’ve built one and shipped it. Keep building.</p>\n","toc":[{"id":"sec-1","text":"What you can do now","level":2},{"id":"sec-2","text":"Make the Watchlist yours","level":2},{"id":"sec-3","text":"What to learn next","level":2}],"takeaways":["Components, props, state, events and Effects are the core of React; everything else builds on them.","Extending your own project with new features is the fastest way to make this course stick.","TypeScript and testing are the two skills that most change how employers read a junior React portfolio.","For data fetching and multi-page apps, reach for established tools such as TanStack Query, React Router or a framework rather than building your own."],"further":[{"title":"React reference overview","url":"https://react.dev/reference/react"},{"title":"Creating a React App (frameworks)","url":"https://react.dev/learn/creating-a-react-app"},{"title":"React Compiler","url":"https://react.dev/learn/react-compiler"},{"title":"Getting Started with Vitest","url":"https://vitest.dev/guide/"}],"quiz":[{"q":"<p>You want to add a “sort by year” option to the Watchlist. Based on this course, what’s the right first design decision?</p>","options":[{"text":"Store the chosen sort order in state and compute a sorted copy of the movies during render.","why":"Correct. The sort order is real state; the sorted list is derived from movies and sort order, so it shouldn’t be stored."},{"text":"Store a sorted copy of the movies in state and update it with an Effect.","why":"That duplicates the movie list and syncs it with an Effect, the exact pattern the course taught you to avoid."},{"text":"Sort the movies array in place with <code dir=\"ltr\">sort</code> before rendering.","why":"In-place sort mutates state. Use <code dir=\"ltr\">toSorted</code> or sort a copy."}],"answer":0},{"q":"<p>A job listing asks for “React, TypeScript, testing”. Which next step adds the most to your Watchlist portfolio project?</p>","options":[{"text":"Rewriting it with class components to show range.","why":"Class components are legacy. Showing them signals outdated knowledge rather than range."},{"text":"Adding more animation libraries.","why":"Polish helps, but it doesn’t address the skills the listing names."},{"text":"Converting it to TypeScript and adding a few component tests with Vitest and React Testing Library.","why":"Correct. Typed props and tests that click through real flows are what reviewers look for in a junior React project."},{"text":"Moving all state into a global store library.","why":"The Watchlist doesn’t need a global store, and adding one without a reason suggests cargo-cult architecture."}],"answer":2},{"q":"<p>Your team turns on the React Compiler. What changes for the code you write?</p>","options":[{"text":"You must wrap every component in <code dir=\"ltr\">memo</code> for the compiler to work.","why":"The compiler does that kind of memoization for you; adding it by hand is what it makes unnecessary."},{"text":"You keep writing plain components that follow the rules of React, and the compiler adds memoization at build time.","why":"Correct. It’s an optional build step. Pure components and correct Hook usage, which you already practise, are what it relies on."},{"text":"Effects are no longer allowed.","why":"Effects still exist and are still for syncing with outside systems. The compiler doesn’t remove any Hook."}],"answer":1}],"exercise":{"kind":"choice","multiple":true,"options":["fetch-in-render","effect-no-deps","effect-ignore-flag","tanstack-query"],"correct":["effect-ignore-flag","tanstack-query"],"title":"Fetching posters the right way","prompt":"<p>Your first stretch feature: when you open a movie’s details, the Watchlist fetches its poster URL from a movie API, using the selected movie’s title. The user can click quickly from one movie to another.</p>\n<p><strong>Pick every approach that would work correctly.</strong></p>\n","hints":["Anything in the component body runs on every render.","If the user switches movies quickly, two requests are in flight. Which one should win?"],"explanation":"<p>Fetching is synchronizing with an outside system, so a hand-written version belongs in an Effect keyed on the title, with a cleanup that marks the old request as stale. Otherwise a slow response for the previous movie can arrive last and overwrite the poster. A data-fetching library such as TanStack Query handles that, plus caching, loading and error states, which is why most real projects use one. Fetching during render or in an Effect with no dependency array sends a request on every render, and setting state from the response triggers another render and another request, with nothing to stop an older response from winning.</p>\n","checkLabels":{},"optionText":{"fetch-in-render":{"text":"Call <code dir=\"ltr\">fetch</code> at the top of the component body and <code dir=\"ltr\">setPoster</code> when it resolves.","why":"The body runs on every render, so every render (including StrictMode’s extra one) sends a request, and each response that sets state causes another render and another request. Rendering must stay pure."},"effect-no-deps":{"text":"Fetch inside <code dir=\"ltr\">useEffect(() =&gt; { … })</code> with no dependency array.","why":"With no array the Effect runs after every render, so each response that sets state triggers another render and another request, and nothing stops a stale response from overwriting the current poster."},"effect-ignore-flag":{"text":"Fetch inside <code dir=\"ltr\">useEffect(…, [title])</code>, with a cleanup that sets <code dir=\"ltr\">ignore = true</code> so a stale response is not saved.","why":"Correct. It refetches only when the title changes, and the cleanup stops an older, slower response from overwriting the current poster."},"tanstack-query":{"text":"Use TanStack Query’s <code dir=\"ltr\">useQuery</code> with the title in the query key.","why":"Correct. The library tracks requests per key, discards outdated ones and adds caching, loading and error states for you."}}},"words":597,"readMinutes":3}