From edcf0e683da21eac313a426b9ed0fb9ea9e0bc2b Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Fri, 22 Sep 2023 10:02:12 +0600 Subject: [PATCH] Add react questions (#4492) * Add more questions * wip: add lazy, conditional questions * wip: Add RSC questions * wip: add component's lifecycle * wip: add dependency array question * wip: add comment and state * chore: add more questions * wip: add list question * wip: add directive questions * fix: conventions and examples * wip: add custom hook question * wip: add hydration question * wip: add error boundary example * wip: add strict mode question * wip: investigating slow react app * Update src/data/question-groups/react/react.md * Update src/data/question-groups/react/react.md --------- Co-authored-by: Kamran Ahmed --- .../react/content/component-lifecycle.md | 32 +++++ .../react/content/custom-hook.md | 51 +++++++ .../react/content/error-boundaries.md | 37 +++++ .../react/content/flush-sync.md | 9 ++ .../react/content/investigate-slow-app.md | 33 +++++ .../react/content/lazy-loading.md | 39 ++++++ .../react/content/render-list.md | 17 +++ .../react/content/strict-mode.md | 19 +++ .../question-groups/react/content/suspense.md | 23 ++++ .../react/content/use-transition.md | 67 ++++++++++ .../react/content/virtual-dom.md | 5 + src/data/question-groups/react/react.md | 126 +++++++++++++++++- 12 files changed, 454 insertions(+), 4 deletions(-) create mode 100644 src/data/question-groups/react/content/component-lifecycle.md create mode 100644 src/data/question-groups/react/content/custom-hook.md create mode 100644 src/data/question-groups/react/content/error-boundaries.md create mode 100644 src/data/question-groups/react/content/flush-sync.md create mode 100644 src/data/question-groups/react/content/investigate-slow-app.md create mode 100644 src/data/question-groups/react/content/lazy-loading.md create mode 100644 src/data/question-groups/react/content/render-list.md create mode 100644 src/data/question-groups/react/content/strict-mode.md create mode 100644 src/data/question-groups/react/content/suspense.md create mode 100644 src/data/question-groups/react/content/use-transition.md create mode 100644 src/data/question-groups/react/content/virtual-dom.md diff --git a/src/data/question-groups/react/content/component-lifecycle.md b/src/data/question-groups/react/content/component-lifecycle.md new file mode 100644 index 000000000..9ec31ad54 --- /dev/null +++ b/src/data/question-groups/react/content/component-lifecycle.md @@ -0,0 +1,32 @@ +In React functional components, lifecycle-like behaviors are achieved using hooks: + +## Mounting and Unmounting + +Utilizing the useEffect hook with an empty dependency array ([]) ensures the hook runs after the component mounts to the DOM. + +```js +useEffect(() => { + // do something after component mounts + return () => { + // do something before component unmounts + }; +}, []); +``` + +The cleanup function returned within the useEffect callback offers a mechanism for handling tasks when the component is about to **unmount**. + +## Updates + +The useEffect hook, when invoked without a dependency array or with specific dependencies, executes after every render or when specified prop/state changes are detected. + +```js +useEffect(() => { + // do something after every render +}); +``` + +```js +useEffect(() => { + // do something after specific prop/state changes +}, [state1, state2]); +``` diff --git a/src/data/question-groups/react/content/custom-hook.md b/src/data/question-groups/react/content/custom-hook.md new file mode 100644 index 000000000..92f92edb5 --- /dev/null +++ b/src/data/question-groups/react/content/custom-hook.md @@ -0,0 +1,51 @@ +**Custom hooks** are a mechanism for code reuse in React and allow you to extract component logic into reusable functions. Custom hooks can be used to share logic between components or to abstract away complex logic to make components more readable. + +Let's look at an example of a custom hook that return network status information: + +## Creating a Custom hook + +Custom hooks are named with the prefix `use` and can call other hooks if needed. They can also accept arguments and return values. + +```js +import { useState, useEffect } from 'react'; + +function useNetworkStatus() { + const [isOnline, setIsOnline] = useState(true); + + useEffect(() => { + function handleOnline() { + setIsOnline(true); + } + + function handleOffline() { + setIsOnline(false); + } + + window.addEventListener('online', handleOnline); + window.addEventListener('offline', handleOffline); + + return () => { + window.removeEventListener('online', handleOnline); + window.removeEventListener('offline', handleOffline); + }; + }, []); + + return isOnline; +} +``` + +The custom hook above uses the `useState` and `useEffect` hooks to track the network status of the browser. It returns a boolean value that indicates whether the browser is online or offline. + +## Using a Custom hook + +```js +function NetworkStatus() { + const isOnline = useNetworkStatus(); + + return ( +
+

You are {isOnline ? 'online' : 'offline'}.

+
+ ); +} +``` diff --git a/src/data/question-groups/react/content/error-boundaries.md b/src/data/question-groups/react/content/error-boundaries.md new file mode 100644 index 000000000..1f5c46ee4 --- /dev/null +++ b/src/data/question-groups/react/content/error-boundaries.md @@ -0,0 +1,37 @@ +Error boundaries are special React components that catch JavaScript errors during rendering, in lifecycle methods, and during the constructor of whole tree below them. They are used to handle errors gracefully by displaying a fallback UI and preventing the entire application from crashing due to unhandled errors. + +You can use [react-error-boundary](https://npm.im/react-error-boundary) package to create error boundaries in your application. It provides a `ErrorBoundary` component that you can wrap around any component that might throw an error. The `ErrorBoundary` component takes a `FallbackComponent` prop that is used to render a fallback UI when an error occurs. + +## Capturing Errors + +```js +import { ErrorBoundary } from 'react-error-boundary'; +import { FetchData } from './FetchData'; + +function ErrorFallback({ error, resetErrorBoundary }) { + return ( +
+

Something went wrong:

+
{error.message}
+ +
+ ); +} + +export function App() { + return ( + + + + ); +} +``` + +This `FetchData` component will throw an error when it is rendered, and the `ErrorBoundary` component will catch the error and display the `ErrorFallback` component. + +```js +export function FetchData() { + throw new Error('Error fetching data'); + return

This will never render

; +} +``` diff --git a/src/data/question-groups/react/content/flush-sync.md b/src/data/question-groups/react/content/flush-sync.md new file mode 100644 index 000000000..41a98e66c --- /dev/null +++ b/src/data/question-groups/react/content/flush-sync.md @@ -0,0 +1,9 @@ +The `flushSync` function in React is used to flush updates synchronously. It schedules updates to be performed inside a high-priority task, ensuring that the updates are executed immediately and synchronously before returning control to the caller. + +```js +import { flushSync } from 'react-dom'; + +flushSync(callback); +``` + +This is useful in situations where you need the DOM to be updated immediately, such as for measurements or to ensure synchronous rendering. However, excessive use of `flushSync` can lead to degraded performance, so it should be used judiciously. diff --git a/src/data/question-groups/react/content/investigate-slow-app.md b/src/data/question-groups/react/content/investigate-slow-app.md new file mode 100644 index 000000000..6493a2c2e --- /dev/null +++ b/src/data/question-groups/react/content/investigate-slow-app.md @@ -0,0 +1,33 @@ +There are many reasons why an app might be slow. It could be due to a slow network, a slow backend, or a slow client. It could also be due to a memory leak, unnecessary re-renders, or large bundle sizes. + +Here are some tips to help you investigate and fix performance issues: + +## Use the React DevTools Profiler + +The React DevTools Profiler helps you visualize how components render and identify costly renderings. It can also help you identify unnecessary re-renders. + +## Check for Unnecessary Renders + +Ensure that components don't render more often than needed. Be clear about the `useEffect` dependencies and avoid creating new objects or arrays every render, as these can trigger unnecessary child component renders. Tools like [why-did-you-render](https://npm.im/@welldone-software/why-did-you-render) can help spot unnecessary re-renders. + +## Analyze Bundle Size + +Use your production build to analyze your bundle size. Tools like [webpack-bundle-analyzer](https://npm.im/webpack-bundle-analyzer) or [source-map-explorer](https://npm.im/source-map-explorer) can help you see if large libraries or unused code is slowing down the initial load. + +## Optimize Images & Assets + +Ensure images are appropriately sized and use modern formats. Also, consider using CDNs for assets that don't change often. + +## Lazy Load Components + +Use `lazy()` and dynamic imports to split your bundle and load components only when they're needed. This can help reduce the initial load time. + +## Check Network Requests + +Slow API calls or fetching large amounts of data can affect performance. Optimize your backend, paginate data, or cache results. You can also use tools like [@tanstack/react-query](https://npm.im/@tanstack/react-query) or [swr](https://npm.im/swr) to help manage data fetching and caching. + +## Use Production Build for Testing + +Ensure you're testing the performance on a production build, as development builds are often slower due to extra checks and logs. + +Regularly profiling and monitoring your app can help you spot and fix performance issues before they become significant problems. You can use tools like [Lighthouse](https://developers.google.com/web/tools/lighthouse) or [Calibre](https://calibreapp.com) to monitor your app's performance over time. diff --git a/src/data/question-groups/react/content/lazy-loading.md b/src/data/question-groups/react/content/lazy-loading.md new file mode 100644 index 000000000..3ddfdadab --- /dev/null +++ b/src/data/question-groups/react/content/lazy-loading.md @@ -0,0 +1,39 @@ +You can use React's `lazy()` function in conjunction with dynamic `import()` to lazily load a component. This is often combined with `Suspense` to display fallback content while the component is being loaded. + +```js +// The component has to be exported as a default export +export default function RoadmapRender() { + return

This is a lazily-loaded component!

; +} +``` + +```js +import { lazy, Suspense } from 'react'; + +const LazyRoadmapRender = lazy(() => delay(import('./RoadmapRender'))); + +export function App() { + const [showRoadmapRender, setShowRoadmapRender] = useState(false); + return ( + <> + + {showRoadmapRender && ( + Loading...}> + + + )} + + ); +} + +// Helper function to simulate a 2 seconds delay +function delay(promise) { + return new Promise((resolve) => setTimeout(resolve, 2000)).then( + () => promise + ); +} +``` + +The `RoadmapRender` component is lazily loaded and rendered inside the `Suspense` component. While the component is being loaded, the `Suspense` component will display the fallback content. diff --git a/src/data/question-groups/react/content/render-list.md b/src/data/question-groups/react/content/render-list.md new file mode 100644 index 000000000..f0241b6a9 --- /dev/null +++ b/src/data/question-groups/react/content/render-list.md @@ -0,0 +1,17 @@ +In React, you can render a list by using the JavaScript `map` function to iterate over an array of items and return a JSX element for each item. It's important to provide a unique `key` prop to each element in the list for React's diffing algorithm to function efficiently during re-renders. Here's a basic example: + +```javascript +const items = ['Apple', 'Banana', 'Cherry']; + +function FruitList() { + return ( + + ); +} +``` + +> Note: While using the index as a key can work in some cases, it's generally not recommended for dynamic lists where items can be added, removed, or reordered. diff --git a/src/data/question-groups/react/content/strict-mode.md b/src/data/question-groups/react/content/strict-mode.md new file mode 100644 index 000000000..9cb1350cc --- /dev/null +++ b/src/data/question-groups/react/content/strict-mode.md @@ -0,0 +1,19 @@ +Strict Mode is a tool in React for highlighting potential problems in an application. By wrapping a component tree with `StrictMode`, React will activate additional checks and warnings for its descendants. This doesn't affect the production build but provides insights during development. + +```js +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; + +const root = createRoot(document.getElementById('root')); +root.render( + + + +); +``` + +In Strict Mode, React does a few extra things during development: + +1. It renders components twice to catch bugs caused by impure rendering. +2. It runs side-effects (like data fetching) twice to find mistakes in them caused by missing effect cleanup. +3. It checks if deprecated APIs are used, and logs a warning message to the console if so. diff --git a/src/data/question-groups/react/content/suspense.md b/src/data/question-groups/react/content/suspense.md new file mode 100644 index 000000000..608c2e803 --- /dev/null +++ b/src/data/question-groups/react/content/suspense.md @@ -0,0 +1,23 @@ +Suspense is a component in React that lets you specify the fallback content to display while waiting for a component to load. It is used in conjunction with `lazy()` to lazily load components. + +```js +import { lazy, Suspense } from 'react'; + +const LazyRoadmapRender = lazy(() => import('./RoadmapRender')); + +export function App() { + const [show, setShow] = useState(false); + return ( + <> + + {show && ( + Loading...}> + + + )} + + ); +} +``` + +Until the `RoadmapRender` component is loaded, the `Suspense` component will display the `Loading...` fallback content. diff --git a/src/data/question-groups/react/content/use-transition.md b/src/data/question-groups/react/content/use-transition.md new file mode 100644 index 000000000..20d8c63b7 --- /dev/null +++ b/src/data/question-groups/react/content/use-transition.md @@ -0,0 +1,67 @@ +`useTransition` hook allows you to mark certain updates as **transitions** so they can be deprioritized, allowing other, more urgent updates to be processed first. This ensures that the UI remains responsive during updates that might take some time. + +```js +import { useTransition, useState } from 'react'; +import { Posts } from './Posts'; +import { Home } from './Home'; +import { Contact } from './Contact'; + +export function App() { + const [isPending, startTransition] = useTransition(); + const [page, setPage] = useState('home'); + + function changePage(newPage: string) { + startTransition(() => { + setPage(newPage); + }); + } + + return ( + <> + + + +
+ {isPending &&
Loading...
} + {page === 'home' && } + {page === 'posts' && } + {page === 'contact' && } + + ); +} +``` + +```js +export function Home() { + return
Home
; +} +``` + +```js +export function Contact() { + return
Contact
; +} +``` + +Posts component is artificially delayed by 500ms to emulate extremely slow code. + +```js +export function Posts() { + const items = []; + for (let i = 0; i < 500; i++) { + items.push(); + } + return
    {items}
; +} + +function SlowPost() { + const startTime = performance.now(); + while (performance.now() - startTime < 1) { + // Do nothing for 1 ms per item to emulate extremely slow code + } + + return
  • Post
  • ; +} +``` + +Now when you click on the `Posts` button, you'll notice that the UI remains responsive and you can still switch to other pages while the posts are loading. Try removing the `startTransition` wrapper around `setPage` in `changePage` to see the difference. diff --git a/src/data/question-groups/react/content/virtual-dom.md b/src/data/question-groups/react/content/virtual-dom.md new file mode 100644 index 000000000..0ec329dc6 --- /dev/null +++ b/src/data/question-groups/react/content/virtual-dom.md @@ -0,0 +1,5 @@ +Virtual DOM works in this steps: + +1. Whenever any underlying data changes, new virtual DOM representation will be created. +2. Then the difference between the previous DOM representation and the new one is calculated. +3. Once the calculations are done, the real DOM will be updated with only the things that have actually changed. diff --git a/src/data/question-groups/react/react.md b/src/data/question-groups/react/react.md index 3468966a3..859a32bfa 100644 --- a/src/data/question-groups/react/react.md +++ b/src/data/question-groups/react/react.md @@ -169,22 +169,140 @@ questions: - 'Performance' - 'Intermediate' - question: Explain the concept of error boundaries in React. - answer: | - Error boundaries are special React components that catch JavaScript errors during rendering, in lifecycle methods, and during the constructor of whole tree below them. They are used to handle errors gracefully by displaying a fallback UI and preventing the entire application from crashing due to unhandled errors. + answer: error-boundaries.md topics: - 'Core' - 'Advanced' - question: What are fragments in React? answer: | React doesn't allow returning multiple elements from a component. You can use fragments to return multiple elements. - + Fragments in React allow for a group of elements to be returned from a component's render method without adding an extra node to the DOM. They are useful when you want to return multiple elements without wrapping them in a parent container. topics: - 'Core' - 'Beginner' - - question: What is `createPortal`? + - question: What are portals in React? answer: create-portal.md topics: - 'Core' - 'Intermediate' + - question: What is Concurrent React (Concurrent Mode)? + answer: | + Concurrent React, previously referred to as Concurrent Mode, is a set of new features in React that allows React to interrupt the rendering process to consider more urgent tasks, making it possible for React to be more responsive to user input and produce smoother user experiences. It lets React keep the UI responsive while rendering large component trees by splitting the rendering work into smaller chunks and spreading it over multiple frames. + topics: + - 'Performance' + - 'Intermediate' + - question: What is the `useTransition` hook? + answer: use-transition.md + topics: + - 'Performance' + - 'Advanced' + - question: What is the purpose of `flushSync` in React? + answer: flush-sync.md + topics: + - 'Core' + - 'Advanced' + - question: How to render React components as static HTML string? + answer: | + The `renderToString` function in React is part of the `react-dom/server` package and is used to render React components on the server-side to a static HTML string. It is commonly used for server-side rendering (SSR) in React. + topics: + - 'SSR' + - 'Intermediate' + - question: What are Server Components in React? + answer: | + Server Components in allow developers to write components that render on the server instead of the client. Unlike traditional components, Server Components do not have a client-side runtime, meaning they result in a smaller bundle size and faster loads. They can seamlessly integrate with client components and can fetch data directly from the backend without the need for an API layer. This enables developers to build rich, interactive apps with less client-side code, improving performance and developer experience. + topics: + - 'SSR' + - 'Intermediate' + - question: How to lazy load components in React? + answer: lazy-loading.md + topics: + - 'Performance' + - 'Intermediate' + - question: What is `Suspense` in React? + answer: suspense.md + topics: + - 'UX' + - 'Intermediate' + - question: How React Virtual DOM works? + answer: virtual-dom.md + topics: + - 'Core' + - 'Intermediate' + - question: How do Server Components differ from Client Components? + answer: Server Components are rendered on the server and do not require client-side JavaScript for rendering. While Server Components and Client components can coexist in the same app, Server Components can import and render Client components. + topics: + - 'SSR' + - 'Beginner' + - question: How do React Server Components handle data fetching? + answer: Server Components can directly access backend resources, databases, or filesystems to fetch data during rendering, eliminating the need for a separate API layer for data fetching. + topics: + - 'SSR' + - 'Beginner' + - question: What's the component's lifecycle in React? + answer: component-lifecycle.md + topics: + - 'Core' + - 'Beginner' + - question: How to write a comment in React? + answer: | + You can write a comment in JSX by wrapping it in curly braces and using JavaScript's multi-line comment syntax. + ```js + {/* This is a comment */} + ``` + topics: + - 'Core' + - 'Beginner' + - question: What is the difference between stateful and stateless components? + answer: | + The main difference between stateful and stateless components is one has state and the other doesn't. Stateful components keep track of changes to their state and re-render themselves when the state changes. Stateless components, on the other hand, render whatever is passed to them via `props` or always render the same thing. + topics: + - 'Core' + - 'Beginner' + - question: Why you shouldn't use `index` as a key in React lists and iterators? + answer: Using `index` as a key can negatively impact performance and may cause issues with the component state. When the list items change due to additions, deletions, or reordering, using indexes can lead to unnecessary re-renders or even incorrect UI updates. React uses keys to identify elements in the list, and if the key is just an index, it might reuse component instances and state inappropriately. Especially in cases where the list is dynamic or items can be reordered, it's recommended to use unique and stable identifiers as keys to ensure consistent behavior. + topics: + - 'Performance' + - 'Beginner' + - question: What is the naming convention for React components? + answer: In React, the naming convention for components is to use PascalCase, meaning the first letter of each word in the component's name should be capitalized. For example, `UserProfile`, `SidebarItem`, or `NavigationMenu`. This convention differentiates custom React components from regular HTML tags in JSX, as React treats elements starting with a lowercase letter as DOM tags and those starting with a capital letter as custom components. + topics: + - 'Core' + - 'Beginner' + - question: How to render a list in React? + answer: render-list.md + topics: + - 'Core' + - 'Beginner' + - question: What are `use client` and `use server` directives? + answer: The `use client` directive marks source files whose components are intended to execute only on the client. Conversely, `use server` marks server-side functions that can be invoked from client-side code. + topics: + - 'SSR' + - 'Intermediate' + - question: Can you use hooks in Server Components? + answer: No, hooks are not supported in Server Components. Hooks are a client-side feature and are not supported in Server Components. However, you can use hooks in client components and import them into Server Components. + topics: + - 'SSR' + - 'Intermediate' + - question: How to create a Custom hook in React? + answer: custom-hook.md + topics: + - 'Core' + - 'Intermediate' + - question: What is Hydration in React? + answer: | + Hydration is the process of using client-side JavaScript to add interactivity to the markup generated by the server. When you use server-side rendering, the server returns a static HTML representation of the component tree. Once this reaches the browser, in order to make it interactive, React "hydrates" the static content, turning it into a fully interactive application. + topics: + - 'SSR' + - 'Intermediate' + - question: What is Strict Mode in React and why is it useful? + answer: strict-mode.md + topics: + - 'Debugging' + - 'Intermediate' + - question: How do you investigate a slow React app and identify performance bottlenecks? + answer: investigate-slow-app.md + topics: + - 'Performance' + - 'Intermediate' ---