skip to Main Content

I’m trying to convert some ReactJS code that was written in a much older version (I think 14 or 16) to 18, and the code uses props.children multiple times, which was removed in the newer versions of ReactJS. I’ve found plenty of tutorials for fixing this, but I can only find ones that refer to functional components, not classes.

export class SystemStatusContainer extends React.Component<
  {},
  {
    status: systemStatuses;
    pollStatus: boolean;
  }
  > {
  state = {
    status: systemStatuses.online,
    pollStatus: true,
  };

  timer: NodeJS.Timeout;
.
.
.
render() {
    const { status } = this.state;

    if (status === systemStatuses.offline) {
      return <SystemUnavailableModal />;
    } else if (status === systemStatuses.update) {
      return <SystemStatusModal />;
    } else {
      return this.props.children;
    }
  }

How do I convert the bottom line, this.props.children, to work in the ReactJS 18? All the methods I found online involve passing children directly into the component, but this only works if it’s a functional component, not a class (from what I can tell).

NOTE: This code is not mine, and because of this, I’m trying to minimize the changes as much as possible. If there are problems in the code unrelated to this question, please do not bring them up unless they will directly impact the problem with this.props.children.

2

Answers


  1. Your code totally works on runtime. This is just a typescript error.

    React did not remove the this.props.children, but you have an error on the previous code because the first argument of React.Component is the type of the props. In there, you didn’t define any prop, not even the children. So the typescript compiler warns you: Property 'children' does not exist on type 'Readonly<{}>'.ts(2339)

    If you define the type properly, the error is gone.

    export class SystemStatusContainer extends React.Component<
      { children: React.ReactNode },
    ...
    

    Take a look at this playground.

    You can specify the children as a named prop or inside the tag:

      <SystemStatusContainer> This is children </SystemStatusContainer>
      <SystemStatusContainer children="This is children too!" />
    

    What changed from React 17 to React 18 are the typings. In react 17, the type Component did include children in the props.

    class Component {
        ...
        readonly props: Readonly<P> & Readonly<{ children?: ReactNode | undefined }>;
    }
    

    In the typings for React 18, props is just a readonly object:

    class Component {
        ...
        readonly props: Readonly<P>;
    }
    
    Login or Signup to reply.
  2. The change in React 18 was to remove children from the type of props by default (both in Component and in the React.FunctionComponent [aka React.FC] type optionally used by function components). It was removed is that not all components should have children (consider a component that ends up rendering just a void element like <br/>).

    If your component has children, it will have a children prop containing those children. So what we have to do is ensure the type of your component’s props says that.

    To make that code work again, declare children in the props type (the first type argument to Component). React provides a utility type, PropsWithChildren, that will add children to a props type. React defines PropsWithChildren like this:

    export type PropsWithChildren<P = unknown> = P & {
        children?: ReactNode | undefined;
    };
    

    So we’d use it on your empty props object type:

    export class SystemStatusContainer extends React.Component<
      PropsWithChildren<{}>, // <=======================
      {
        status: systemStatuses;
        pollStatus: boolean;
      }
      > {
      state = {
        status: systemStatuses.online,
        pollStatus: true,
      };
      // ...
    

    Here’s a very basic example (on the TypeScript playground):

    import { Component, PropsWithChildren } from "react";
    
    class Example extends Component<PropsWithChildren<{}>, {}> {
        render() {
            return this.props.children;
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search