Skip to content

Instantly share code, notes, and snippets.

@kitze
Created October 25, 2017 16:54
Show Gist options
  • Star 97 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save kitze/23d82bb9eb0baabfd03a6a720b1d637f to your computer and use it in GitHub Desktop.
Save kitze/23d82bb9eb0baabfd03a6a720b1d637f to your computer and use it in GitHub Desktop.
one-line React component for conditionally wrapping children
import React from 'react';
const ConditionalWrap = ({condition, wrap, children}) => condition ? wrap(children) : children;
const Header = ({shouldLinkToHome}) => (
<div>
<ConditionalWrap
condition={shouldLinkToHome}
wrap={children => <a href="/">{children}</a>}
>
<img src="logo.png"/>
</ConditionalWrap>
</div>
)
@TheBox193
Copy link

Some Unit tests:

describe('ConditionalWrap', () => {
	it('Should wrap when true', () => {
		const wrapper = shallow(
			<ConditionalWrap condition={true} wrap={children => <a href='/'>{children}</a>} >
				<img src='image.png' />
			</ConditionalWrap>
		);

		expect(wrapper.find('a').length).toBe(1);
		expect(wrapper.find('img').length).toBe(1);
	});
	it('Should not wrap when false', () => {
		const wrapper = shallow(
			<ConditionalWrap condition={false} wrap={children => <a href='/'>{children}</a>} >
				<img src='image.png' />
			</ConditionalWrap>
		);

		expect(wrapper.find('a').length).toBe(0);
		expect(wrapper.find('img').length).toBe(1);
	});
	it('Should not wrap when undefined', () => {
		const wrapper = shallow(
			<ConditionalWrap wrap={children => <a href='/'>{children}</a>} >
				<img src='image.png' />
			</ConditionalWrap>
		);

		expect(wrapper.find('a').length).toBe(0);
		expect(wrapper.find('img').length).toBe(1);
	});
});

@RedTn
Copy link

RedTn commented Nov 2, 2018

This fails if condition = false, and you are returning more than one child on React 15, if so I would change line 3 to

const ConditionalWrap = ({condition, wrap, children}) => condition ? wrap(children) : <div>children</div>;

@peacefulseeker
Copy link

peacefulseeker commented Jan 2, 2019

This fails if condition = false, and you are returning more than one child on React 15, if so I would change line 3 to

const ConditionalWrap = ({condition, wrap, children}) => condition ? wrap(children) : <div>children</div>;

or even using new React Fragments short syntax;
https://reactjs.org/docs/fragments.html#short-syntax

const ConditionalWrap = ({condition, wrap, children}) => condition ? wrap(children) : <>{children}</>;

@Jianyi-Ren
Copy link

Thanks for sharing the unit test! How would you test the ConditionalWrap if it is defined within component render(){}?

@arunmmanoharan
Copy link

Can someone provide a typescript version for this?
This is what I have:

import React, { FunctionComponent } from 'react';

interface IConditionalWrapProps {
  condition: boolean;
  wrap: Function;
  children: React.ReactNode;
}

const ConditionalWrap: FunctionComponent<IConditionalWrapProps> = ({
  condition,
  wrap,
  children,
}) => (condition ? wrap(children) : <>{children}</>);

export default ConditionalWrap;

Please let me know if this suffices.

@kitze
Copy link
Author

kitze commented Aug 6, 2020

@jensbodal
Copy link

typescript version:

type ConditonalWrapperProps = {
  children: React.ReactElement;
  condition: boolean;
  wrapper: (children: React.ReactElement) => JSX.Element;
};
const ConditonalWrapper: React.FC<ConditonalWrapperProps> = ({ condition, wrapper, children }) =>
  condition ? wrapper(children) : children

@kitze
Copy link
Author

kitze commented Nov 16, 2020

@jensbodal thanks but the types are in the package already

@pvinis
Copy link

pvinis commented Dec 22, 2021

an even better api, and the way i use it is:

<Wrap
  if={someCondition}
  with={ch => <View>{ch}</View>}
>
  <Text />
</Wrap>

@pvinis
Copy link

pvinis commented Dec 22, 2021

here we go, nice TS code

import React, { FC } from "react"

interface WrapProps {
  if: boolean
  with: (children: React.ReactNode) => JSX.Element
}

export const Wrap: FC<WrapProps> = ({ if: condition, with: wrapper, children }) => {
  return condition ? wrapper(children) : <>children</>
}

@misha-erm
Copy link

misha-erm commented Mar 11, 2022

check out https://github.com/kitze/conditional-wrap

@kitze Small question)) For what reasons React.cloneElement is used?

@hnrq
Copy link

hnrq commented Jun 22, 2022

I have an improvement suggestion for this:

import { FC, ReactNode, createElement } from 'react';

interface WrapProps {
	if?: boolean;
	with: typeof createElement.arguments[0];
	wrapperProps: typeof createElement.arguments[1];
	children: NonNullable<ReactNode>;
}

const Wrap: FC<WrapProps> = ({
	if: condition,
	with: wrapper,
	wrapperProps,
	children,
}) =>
	condition ? createElement(wrapper, wrapperProps, [children]) : <>children</>;

export default Wrap;

By using createElement we can use Wrap like so:

<Wrap if={condition} with="a" wrapperProps={{ 'data-testid': 'wrapper' }}>
    <p>Wrapped text</p>
</Wrap>

Instead of always passing a (children) => <jsx /> function.

@badalsaibo
Copy link

FYI this function breaks the react/no-unstable-nested-components eslint rule.

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