A Flashback to React 18 Features

Notes on react 18 features

4 min read

.

Mar 23, 2023


In this blog post, we'll take a flashback to explore the key features introduced in React 18, understanding how they empower developers to craft better user experiences and streamline development workflows.

  1. Server components - one key highlight in react 18th release is react server components. Server components allow developers to render on the server, reducing the amount of javascript being sent to the client. This is a performance improvement while reducing the initial load time.

So how does react server components differ from nextjs server side rendering. While both react server components and nextjs server side rendering are two techniques to generate react components on the server they possess few key differences.

  • Rendering Approach: React Server Components are rendered on the server and sent to the client as HTML. They do not include any JavaScript related to the component. Next.js SSR renders the entire page on the server and sends the result along with the necessary JavaScript to the client. The client then "hydrates" the page to make it fully interactive.

  • Interactivity: React Server Components are not interactive on their own. They rely on other components (either Client Components or Shared Components) for interactivity. In contrast, Next.js SSR pages are fully interactive once they are hydrated on the client.

  • Data Fetching: With React Server Components, you can fetch data in the component itself, and only the final HTML is sent to the client. With Next.js SSR, you fetch data in a getServerSideProps function, and the data is passed as props to your page component.

  • Routing: Next.js has built-in support for routing, including dynamic routes. React Server Components do not include routing; you would need to handle that separately, perhaps with a library like React Router.

  • Zero-Bundle-Size Components: React Server Components have a unique advantage in that they can import other modules without adding to the client-side bundle size, as they are not sent to the client. This is made possible because React Server Components are executed on the server and their output is sent to the client, rather than sending the component code itself.

So how to interact with javascript with react server components?

React Server Components are designed to render HTML on the server and send it to the client. They do not include any client-side JavaScript. However, you can still handle events like button clicks by using a mix of Server Components and Client Components.

// Server Component
function MyServerComponent() {
  return (
    <div>
      <h1>Hello from Server Component</h1>
      <MyClientComponent />
    </div>
  );
}

// Client Component
function MyClientComponent() {
  const [data, setData] = React.useState(null);

  const fetchData = async () => {
    const response = await fetch('/api/data');
    const data = await response.json();
    setData(data);
  };

  return (
    <div>
      <button onClick={fetchData}>Fetch Data</button>
      {data && <div>{JSON.stringify(data)}</div>}
    </div>
  );
}

In this example, MyServerComponent is a Server Component that includes MyClientComponent. MyClientComponent is a Client Component that fetches data when a button is clicked and displays the data.

Remember, Server Components can render Client Components, but Client Components cannot render Server Components. Also, Server Components are still experimental and not yet available in a stable release of React.

  1. React Streaming Server Renderer: This new feature allows React to start sending HTML to the browser while the server component is still "thinking" (i.e., while components are still being rendered on the server).

  2. Concurrent Rendering: This is a new mode that allows React to work on multiple tasks at once without blocking the main thread, leading to smoother user interfaces.

  3. Suspense: This feature, which was partially available in React 17, is now fully supported. It allows components to "wait" for something before they render.

// App.js
import React, { Suspense } from 'react';
import { fetchData } from './api'; // Assume this is an API function for fetching data

// Lazy-loaded component
const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
  // Data fetching using Suspense
  const dataPromise = fetchData(); // Fetch data asynchronously
  const data = dataPromise.read(); // Suspense will pause rendering until data is fetched

  return (
    <div>
      <h1>Server-Side Rendering with Suspense</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyComponent />
      </Suspense>
      <div>Data: {data}</div>
    </div>
  );
}

export default App;
  1. Automatic batching: In React 18, multiple state updates from the same event handler will be batched automatically, not only in React event handlers but also in asynchronous functions.

  2. React.startTransition: This new API allows you to mark certain updates as "transitions", giving them lower priority. If a transition update takes a long time, React keeps the previous screen interactive with the same state.

  3. useSyncExternalStore: This is a new hook that is designed to work with external (non-React) state.

  4. Root API: This new API provides more control over the rendering of your app. It replaces the old ReactDOM.render() and ReactDOM.hydrate().

import { createRoot } from 'react-dom';

// Create a root container for rendering
const rootContainer = document.getElementById('root');

// Create a root using the createRoot function
const root = createRoot(rootContainer);

// Define a simple functional component
function App() {
  return <h1>Hello, React 18!</h1>;
}

// Render the component using the root API
root.render(<App />);