react-17-to-18

Upgrade your React 17 project to React 18

Example

# https://react.dev/blog/2022/03/08/react-18-upgrade-guide

constants:
  react_version: '18.3.1'

setup:
  - name: run_terminal_command
    arguments:
      command: npm install react@{{ react_version }} react-dom@{{ react_version }}
  - name: run_terminal_command
    arguments:
      command: yarn add react@{{ react_version }} react-dom@{{ react_version }}

steps:
  - name: Update Client Rendering APIs
    tools:
      - name: find_files_by_name_with_regex
        arguments:
          path_to_directory: 'src'
          find_file_name_pattern: '\.jsx?$'
        returns: react_files
      - name: async_each
        items: '{{ react_files }}'
        each_item:
          item_name: react_file
          tools:
            - name: edit_file_with_context_snippets
              arguments:
                path_to_file: '{{ react_file }}'
                context_snippets:
                  - snippet: |
                      import { render } from 'react-dom';
                      const container = document.getElementById('app');
                      render(<App tab="home" />, container);
                  - snippet: |
                      import { createRoot } from 'react-dom/client';
                      const container = document.getElementById('app');
                      const root = createRoot(container);
                      root.render(<App tab="home" />);
                edit_prompt: |
                  Replace the render function from 'react-dom' with the createRoot function from 'react-dom/client'.
  - name: Update unmountComponentAtNode
    tools:
      - name: async_each
        items: '{{ react_files }}'
        each_item:
          item_name: react_file
          tools:
            - name: edit_file_with_context_snippets
              arguments:
                path_to_file: '{{ react_file }}'
                context_snippets:
                  - snippet: |
                      unmountComponentAtNode(container);
                  - snippet: |
                      const root = createRoot(container);
                      root.unmount();
                edit_prompt: |
                  Replace unmountComponentAtNode with root.unmount.

  - name: Update Callback in render
    tools:
      - name: async_each
        items: '{{ react_files }}'
        each_item:
          item_name: react_file
          tools:
            - name: edit_file_with_context_snippets
              arguments:
                path_to_file: '{{ react_file }}'
                context_snippets:
                  - snippet: |
                      render(<App tab="home" />, container, () => {
                        console.log('rendered');
                      });
                  - snippet: |
                      function AppWithCallbackAfterRender() {
                        useEffect(() => {
                          console.log('rendered');
                        });

                        return <App tab="home" />;
                      }

                      const container = document.getElementById('app');
                      const root = createRoot(container);
                      root.render(<AppWithCallbackAfterRender />);
                edit_prompt: |
                  Replace the callback function in render with a useEffect hook inside a new component.

  - name: Update Server-Side Rendering
    tools:
      - name: find_files_by_name_with_regex
        arguments:
          path_to_directory: 'src'
          find_file_name_pattern: '\.jsx?$'
        returns: react_files
      - name: async_each
        items: '{{ react_files }}'
        each_item:
          item_name: react_file
          tools:
            - name: edit_file_with_context_snippets
              arguments:
                path_to_file: '{{ react_file }}'
                context_snippets:
                  - snippet: |
                      import { hydrate } from 'react-dom';
                      const container = document.getElementById('app');
                      hydrate(<App tab="home" />, container);
                  - snippet: |
                      import { hydrateRoot } from 'react-dom/client';
                      const container = document.getElementById('app');
                      const root = hydrateRoot(container, <App tab="home" />);
                edit_prompt: |
                  Replace the hydrate function from 'react-dom' with the hydrateRoot function from 'react-dom/client'.

  - name: Update TypeScript Definitions
    tools:
      - name: run_terminal_command
        arguments:
          command: npm install @types/react@latest @types/react-dom@latest

  - name: Handle Automatic Batching
    tools:
      - name: async_each
        items: '{{ react_files }}'
        each_item:
          item_name: react_file
          tools:
            - name: edit_file_with_context_snippets
              arguments:
                path_to_file: '{{ react_file }}'
                context_snippets:
                  - snippet: |
                      setTimeout(() => {
                        setCount(c => c + 1);
                        setFlag(f => !f);
                      }, 1000);
                  - snippet: |
                      setTimeout(() => {
                        setCount(c => c + 1);
                        setFlag(f => !f);
                      }, 1000);
                      // After React 18, this update will be batched automatically.
                edit_prompt: |
                  Ensure that all updates inside timeouts, promises, and native event handlers are batched.

  - name: Update Testing Environment
    tools:
      - name: edit_file
        arguments:
          path_to_file: 'src/setupTests.js'
          edit_prompt: |
            Add the following line to the setup file to configure the testing environment for React 18:
            globalThis.IS_REACT_ACT_ENVIRONMENT = true;

  - name: Update Scripts in package.json
    tools:
      - name: edit_file
        arguments:
          path_to_file: 'package.json'
          edit_prompt: |
            {
              "scripts": {
                "dev": "next dev",
                "build": "next build",
                "start": "next start"
              }
            }

Last updated