React-React extras v2.0.0: Useful components and utilities for working with React

icon
Latest Release: v2.0.0

Breaking

  • Require Node.js 10 e7b750a
  • Output build as ESM module (#14) ac7fb55

https://github.com/sindresorhus/react-extras/compare/v1.0.1...v2.0.0

Source code(tar.gz)
Source code(zip)

react-extras Build Status

Useful components and utilities for working with React

Install

$ npm install react-extras

Usage

import React from 'react';
import {If} from 'react-extras';

const App = props => (
	<If condition={props.showUnicorn}>
		<div className="unicorn">
			?
		</div>
	</If>
);

API

autoBind(self, [options])

Automatically binds your React.Component subclass methods to the instance. See the autoBind.react() docs.

classNames(…input)

Conditionally join CSS class names together.

input

Type: string Object

Accepts a combination of strings and objects. Only object keys with truthy values are included. Anything else is ignored.

classNames('unicorn', 'rainbow');
//=> 'unicorn rainbow'

classNames({awesome: true, foo: false}, 'unicorn', {rainbow: false});
//=> 'awesome unicorn'

classNames('unicorn', null, undefined, 0, 1, {foo: null});
//=> 'unicorn'

const buttonType = 'main';
classNames({[`button-${buttonType}`]: true});
//=> 'button-main'
const Button = props => {
	console.log(props);
	/*
	{
		type: 'success',
		small: true
	}
	*/

	const buttonClass = classNames(
		'button',
		{
			[`button-${props.type}`]: props.type,
			'button-block': props.block,
			'button-small': props.small
		}
	);

	console.log(buttonClass);
	//=> 'button button-success button-small'

	return <button className={buttonClass}>…</button>;
};

<If>

React component that renders the children if the condition prop is true.

Beware that even though the children are not rendered when the condition is false, they're still evaluated.

If you need it to not be evaluated on false, you can pass a function to the render prop that returns the children:

<div>
	<If condition={props.error} render={() => (
		<h1>{props.error}</h1>
	)}/>
</div>

Or you could just use plain JavaScript:

<div>
	{props.error && (
		<h1>{props.error}</h1>
	)}
</div>

<Choose>

React component similar to a switch case. <Choose> has 2 children components:

  • <Choose.When> that renders the children if the condition prop is true.
  • <Choose.Otherwise> that renders the children if has no <Choose.When> with true prop condition.

Note that even when the children are not rendered, they're still evaluated.

<div>
	<Choose>
		<Choose.When condition={props.success}>
			<h1>{props.success}</h1>
		</Choose.When>
		<Choose.When condition={props.error}>
			<h1>{props.error}</h1>
		</Choose.When>
		<Choose.Otherwise>
			<h1>?</h1>
		</Choose.Otherwise>
	</Choose>
</div>

Or you could just use plain JavaScript:

<div>
	{(() => {
		if (props.success) {
			return <h1>{props.success}</h1>;
		}

		if (props.error) {
			return <h1>{props.error}</h1>;
		}

		return <h1>?</h1>;
	})()}
</div>

<For/>

React component that iterates over the of prop and renders the render prop.

<div>
	<For of={['?', '?', '?']} render={(item, index) =>
		<button key={index}>{item}</button>
	}/>
</div>

Or you could just use plain JavaScript:

<div>
	{['?', '?', '?'].map((item, index) =>
		<button key={index}>{item}</button>
	)}
</div>

<Image/>

React component that improves the <img> element.

It makes the image invisible if it fails to load instead of showing the default broken image icon. Optionally, specify a fallback image URL.

<Image
	url="https://sindresorhus.com/unicorn.jpg"
	fallbackUrl="https://sindresorhus.com/rainbow.jpg"
/>

It supports all the props that <img> supports, but you use the prop url instead of src.

<RootClass/>

Renderless React component that can add and remove classes to the root <html> element. It accepts an add prop for adding classes, and a remove prop for removing classes. Both accept either a single class or multiple classes separated by space.

<If condition={props.isDarkMode}>
	<RootClass add="dark-mode"/>
</If>
<RootClass add="logged-in paid-user" remove="promo"/>

<BodyClass/>

Same as <RootClass/> but for <body>.

Prefer <RootClass/> though, because it's nicer to put global classes on <html> as you can consistently prefix everything with the class:

.dark-mode body {
	background: #000;
}

.dark-mode a {
	…
}

With <BodyClass/> you need to do:

body.dark-mode {
	background: #000;
}

.dark-mode a {
	…
}

isStatelessComponent(Component)

Returns a boolean of whether the given Component is a functional stateless component.

getDisplayName(Component)

Returns the display name of the given Component.

canUseDOM

A boolean of whether you're running in a context with a DOM. Can be used to check if your component is running in the browser or if it's being server-rendered.

Related

License

MIT © Sindre Sorhus

Comments

  • I had an error updating to version 2
    I had an error updating to version 2

    Apr 11, 2020

    Hello guys, I use Next with Typescript and when upgrading to version 2, I had this error: Screenshot_2020-04-10_22-36-15 Does anyone have any suspicions?

    Reply
  • Jest fails to load files for version 2
    Jest fails to load files for version 2

    May 6, 2020

    Hi,

    I am using a react app with create-react-app using Typescript including Jest to run some unit tests with @testing-library/react that includes components that use "react-extras".

    When updating the version of react extras from 1.0.1 to 2.0.0, I encountered the issue:

    Test suite failed to run
    
        Jest encountered an unexpected token
    
        This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
    
        By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
    
        Here's what you can do:
         • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
         • If you need a custom transformation specify a "transform" option in your config.
         • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
    
        You'll find more details and examples of these config options in the docs:
        https://jestjs.io/docs/en/configuration.html
    
        Details:
    
        C:\rtc\products\ev_main\weert\prod\Anywhere\node_modules\react-extras\dist\index.js:1
        ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export { default as autoBind } from 'auto-bind/react';
                                                                                                 ^^^^^^
    
        SyntaxError: Unexpected token 'export'
    
          4 | import { Trans } from "react-i18next";
          5 | import { FormLabelStyle } from "../../Theming/UserFormStyles";
        > 6 | import { If } from "react-extras";
            | ^
          7 | 
          8 | interface CubusUserFormGroupProps {
          9 |   labelI18nKey?: string;
    
          at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:537:17)
          at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:579:25)
          at Object.<anonymous> (src/Utilities/UserForms/CubusUserFormGroup.tsx:6:1)
    

    Node version: 12.16.1

    My first assumption would be that it is related to the change "Output build as ESM module (#14)", but honestly I don't know too much about it. Do I need to apply some custom transformation to it as suggested by the hint?

    Reply
  • Add `<Choose>` component
    Add `` component

    Jan 25, 2018

    I was inspired by https://github.com/AlexGilleran/jsx-control-statements (I love this babel plugin) and I created the <Choose /> component. It is similar to a switch case.

    Reply
  • Add documentation comments and tests for the TypeScript definition
    Add documentation comments and tests for the TypeScript definition

    Sep 3, 2018

    Issuehunt badges

    To improve the TS definition.

    See https://github.com/sindresorhus/typescript-definition-style-guide on how to do it.


    IssueHunt Summary

    notwoods notwoods has been rewarded.

    Backers (Total: $20.00)

    Submitted pull Requests


    Tips


    IssueHunt has been backed by the following sponsors. Become a sponsor

    enhancement help wanted good first issue :gift: Rewarded on Issuehunt 
    Reply
  • Add TypeScript type definitions
    Add TypeScript type definitions

    Mar 16, 2018

    Added type definition for use with TypeScript. Without these there is no compile time checking when using TypeScript to build a React application.

    Not sure why the unit test fails now with a 7:1 Do not reference the index file directly unicorn/import-index. Not something I touched.

    Reply
  • Use ESM for build
    Use ESM for build

    Dec 8, 2019

    I have been successfully using react-extras v0.7.1 for the past year or so. Today, I tried to upgrade to a more recent version but the build failed. Rollup is having trouble importing components from react-extras v0.9.0 and later due to the convoluted way that Babel is defining the CommonJS exports.

    Click here to see the strack trace from Rollup
    [!] Error: 'Choose' is not exported by node_modules/react-extras/dist/index.js
    https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module
    lib/components/payment/payment-preview.jsx (3:9)
    1: import React, { useEffect, useState } from 'react';
    2: import PropTypes from 'prop-types';
    3: import { Choose } from 'react-extras';
                ^
    4: import { Dimmer, Loader, Message } from 'semantic-ui-react';
    5: import { load } from '../../constants';
    Error: 'Choose' is not exported by node_modules/react-extras/dist/index.js
        at error (/Users/sholladay/Code/<redacted>/client/node_modules/rollup/dist/rollup.js:5363:30)
        at Module.error (/Users/sholladay/Code/<redacted>/client/node_modules/rollup/dist/rollup.js:9701:9)
        at handleMissingExport (/Users/sholladay/Code/<redacted>/client/node_modules/rollup/dist/rollup.js:9618:21)
        at Module.traceVariable (/Users/sholladay/Code/<redacted>/client/node_modules/rollup/dist/rollup.js:10011:17)
        at ModuleScope.findVariable (/Users/sholladay/Code/<redacted>/client/node_modules/rollup/dist/rollup.js:8678:39)
        at ReturnValueScope.findVariable (/Users/sholladay/Code/<redacted>/client/node_modules/rollup/dist/rollup.js:3054:38)
        at ChildScope.findVariable (/Users/sholladay/Code/<redacted>/client/node_modules/rollup/dist/rollup.js:3054:38)
        at Identifier$1.bind (/Users/sholladay/Code/<redacted>/client/node_modules/rollup/dist/rollup.js:4392:40)
        at CallExpression$1.bind (/Users/sholladay/Code/<redacted>/client/node_modules/rollup/dist/rollup.js:3137:31)
        at CallExpression$1.bind (/Users/sholladay/Code/<redacted>/client/node_modules/rollup/dist/rollup.js:6643:15)
    

    Notably, with v0.9.0, node_modules/react-extras/dist/index.js contains:

    Object.defineProperty(exports, "Choose", {
      enumerable: true,
      get: function get() {
        return _choose.default;
      }
    });
    

    Whereas, with previous versions, it was simply:

    exports.Choose = Choose;
    

    This change was introduced in https://github.com/sindresorhus/react-extras/commit/48b3170d8581dae942841f9c1c7dc9a959c15d8f.

    Needless to say, the former is much harder to statically analyze than the latter. We could try to blame Rollup for not being sophisticated enough, but it doesn't surprise me that it is having trouble with this.

    I think the best solution would be for react-extras to publish a build in ES modules format. That way it's easier for modern bundlers to import.

    enhancement help wanted 
    Reply
  • add tag property
    add tag property

    Jan 18, 2018

    null

                                                                                                                                                                                                           
    Reply
  • Output build as ESM modules
    Output build as ESM modules

    Feb 27, 2020

    Fixes #13

    This PR updates the build process to produce ES modules instead of CommonJS modules, by removing @babel/preset-env and its ESM -> CommonJS transform, which will make it easier for modern ESM-based bundlers (such as Rollup) to import, analyze, and bundle the code, as the exports are statically analyzable. This will also enable tree-shaking in modern bundlers, leading to smaller bundle sizes.

    Currently, this PR also includes two minor improvements to the build/testing process that are unrelated:

    • Removes the babel-eslint custom parser for XO, as it is unnecessary these days.
    • Switches from prepublishOnly to prepare for the npm script responsible for automatically building the package (see the docs). This makes it so the package will be built for local npm install during development and also makes it so that the package will be built if installed as a git dependency (something I tend to do a lot when debugging).
    Reply