Skip to content

Instantly share code, notes, and snippets.

@nathansmith
Last active October 13, 2021 17:13
Show Gist options
  • Save nathansmith/521059b2221c8070d0b703691e13c9cf to your computer and use it in GitHub Desktop.
Save nathansmith/521059b2221c8070d0b703691e13c9cf to your computer and use it in GitHub Desktop.
React component to conditionally (not) render child components.
/*
// Used like so…
<Render if={isUserAuthenticated}>
<p>
Super secret UI.
</p>
</Render>
*/
import React from 'react';
import PropTypes from 'prop-types';
const Render = ({
children = null,
if: isTruthy = false,
}) => {
// Assume falsy.
let content = null;
// Truhty?
if (isTruthy) {
content = children;
}
// Expose UI.
return <>{content}</>;
}
Render.propTypes = {
children: PropTypes.node,
if: PropTypes.any,
};
export default Render;
/*
// Used like so…
<Render if={isUserAuthenticated}>
<p>
Super secret UI.
</p>
</Render>
*/
import React from 'react';
// ======
// Types.
// ======
export interface RenderProps {
/* eslint-disable @typescript-eslint/no-explicit-any */
children: any;
if: any;
/* eslint-enable @typescript-eslint/no-explicit-any */
}
// ==========
// Component.
// ==========
const Render: React.FC<RenderProps> = ({
// Props.
children = null,
if: isTruthy = false,
}) => {
// Assume falsy.
let content = null;
// Truhty?
if (isTruthy) {
content = children;
}
// Expose UI.
return <>{content}</>;
};
export default Render;
import React from 'react';
import { render } from 'react-dom';
// Test subject.
import Render, { RenderProps } from './Render';
// ====================
// Describe `fileName`.
// ====================
describe('Render.tsx', () => {
// ======================
// Test default scenario.
// ======================
test('handles default scenario', () => {
// Dummy text.
const DUMMY_TEXT = 'DUMMY_TEXT';
// Dummy props.
const props: RenderProps = {
children: <p>{DUMMY_TEXT}</p>,
if: true,
};
// Render.
const component = <Render {...props} />;
const container = document.createElement('div');
render(component, container);
// Get elements.
const child = container.querySelector('p') as HTMLElement;
// Test assertions.
expect(child.textContent).toBe(DUMMY_TEXT);
});
// ====================
// Test falsy scenario.
// ====================
test('handles falsy scenario', () => {
// Dummy text.
const DUMMY_TEXT = 'DUMMY_TEXT';
// Dummy props.
const props: RenderProps = {
children: <p>{DUMMY_TEXT}</p>,
if: false,
};
// Render.
const component = <Render {...props} />;
const container = document.createElement('div');
render(component, container);
// Get elements.
const child = container.querySelector('p') as HTMLElement;
// Test assertions.
expect(child).toBe(null);
});
});
@nathansmith
Copy link
Author

nathansmith commented Sep 29, 2017

New hotness:

const errorMessage = "No wrapping element if I don't exist!";

// No empty `<p>` tag.
return (
  <Render if={errorMessage}>
    <p>
      {errorMessage}
    </p>
  </Render>
);

Old and busted:

const errorMessage = "No wrapping element if I don't exist!";

// No empty `<p>` tag.
return (
  errorMessage ? (
    <p>
      {errorMessage}
    </p>
  ) : null
);

Also old and busted:

let errorMessage = "No wrapping element if I don't exist!";

// No empty `<p>` tag.
if (errorMessage) {
  errorMessage = (
    <p>
      {errorMessage}
    </p>
  );
}

return errorMessage || null;

What we're trying to avoid:

const errorMessage = "Unnecessary element if I don't exist!";

// Possibly empty `<p>` tag.
return (
  <p>
    {errorMessage}
  </p>
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment