Conditionally render a React component depending on a descendant's render

59 Views Asked by At

We use Reakit dialogs to prompt users to take an action in our React web app.

On some pages, we have specific text related to the action and would like to render this specific content in the dialog. On all other pages, we want to fall back to generic text.

Our simplified component hierarchy for generic pages looks like:

<BaseLayout>
  ...
</BaseLayout>

and for a page where we want to show specific text,

<BaseLayout>
  ...
  <SpecificPage/>
  ...
</BaseLayout>

What we'd like to happen is:

  1. On pages that render the SpecificPage component, the Dialog appears with the specific text
  2. On pages that do not render the SpecificPage component, the Dialog appears with the fallback generic text

Our approach was to have the SpecificPage component render a Dialog with the page-specific text, and the BaseLayout component render a Dialog with the generic fallback text, but this approach isn't ideal -- users see a flash of the BaseLayout dialog before the SpecificPage dialog is rendered. Is there any way to define a single component that is "overridden" by descendants in the component hierarchy, or other way to achieve this conditional rendering?

2

There are 2 best solutions below

0
On BEST ANSWER

See https://github.com/ariakit/ariakit/discussions/1266#discussioncomment-2617748 for a solution and CodeSandbox that solves this problem well using the Constate library.

0
On

You can simply check if you're rendering anything as children in the BaseLayout component or not, If not you can fallback to generic text.

Here's an example.

App Component

import React from 'react';
import { BaseLayout } from './BaseLayout';

export function App(props) {
  return (
    <div className='App'>
      <BaseLayout>
        <h1>Hello World.</h1>
      </BaseLayout>. // Renders hello world
      <BaseLayout /> // Render generic text
    </div>
  );
}

Base Layout Component

import React from 'react';
export function BaseLayout({children}) {
  return (
    <div>
      {children ? children : "Some Generic Text"}
    </div>
  );
}