Today I Learned

A Hashrocket project

94 posts about #react

Test Files In create-react-app

Any .js files placed in the __tests__ directory will be treated as tests by Jest when running yarn test. If you don’t want to place all of your files in that directory and especially if you want to co-located your test files with the source files, you can name them with the .test.js or .spec.js suffixes.

Any files in your create-react-app project ending in these suffixes will be treated by Jest as test files and included in test runs.

There are more details in the docs.

Firing the blur event when a component unmounts

If an input is focused and a React component containing that input unmounts, then the blur event for that input will not fire. If you use the blur event to save the contents of the input then you are in trouble.

You can know what input/select on the page currently has the focus with document.activeElement. Combine that with the component lifecycle method componentWillUnmount() to fire blur for the currently focused element on unmount.

componentWillUnmount() {
  const input = document.activeElement()
  input.blur()
}

The documentation for activeElement says it may return <body> or null when there is no active element, so you need to protect against that.

componentWillUnmount() {
  const input = document.activeElement()
  if (input) {
    input.blur()
  }
}

Enforce Specific Values With PropTypes

Being able to constrain our user interfaces to very specific values is valuable. This makes our interfaces easier to reason about and easier to test. PropTypes in general are one of the ways that we constrain our UIs. We can go even further than simple type constraints by limiting a prop to a specific set of values, an enum if you will.

MyComponent.propTypes = {
  flavor: PropTypes.oneOf(['Vanilla', 'Chocolate', 'Strawberry']),
};

The docs say about oneOf():

You can ensure that your prop is limited to specific values by treating it as an enum.

If we use MyComponent with a value such as Pistachio, we’ll have a console warning to answer for.

source

A React Component Is Just A Bag Of Data

If you write enough React using JSX, it is easy to forget that you’re not working with markup. Everything — divs, h1s, 3rd party components, your components — all get boiled down to JavaScript objects full of data.

Any given React component is really just a bag of data. Try doing a console.log to see. Here is an example from an earlier post.

const ParentWithClick = ({ children }) => {
  return (
    <React.Fragment>
      {React.Children.map(children || null, (child, i) => {
        console.log(child);
        return <child.type {...child.props} key={i} onClick={handleClick} />;
      })}
    </React.Fragment>
  );
};

const App = () => (
  <div>
    <ParentWithClick>
      <span>Click this span</span>
    </ParentWithClick>
  </div>
);

Looking in the console, we see the following output:

Object {type: "span", key: null, ref: null, props: Object, _owner: Object…}
 type: "span"
 key: null
 ref: null
 props: Object
  children: "Click this span"
 _owner: Object
 _store: Object

It contains information about the component itself and because of the tree structure of this data, you could potentially expand the props —> children sections several times for certain components.

See a live example here.

Mapping Over One Or Many Children In React

In Dynamically Add Props To A Child Component, I talked about how a child element can be reconstituted with additional props. The approach I showed will only work in the case of a single child being nested in that component. What if you want your component to account for one, many, or even children?

React comes with a built-in function for mapping that handles these cases.

const ParentWithClick = ({ children }) => {
  return (
    <React.Fragment>
      {React.Children.map(children || null, (child, i) => {
        return <child.type {...child.props} key={i} onClick={handleClick} />;
      })}
    </React.Fragment>
  );
};

The React.Children.map function allows mapping over one or many elements and if children is null or undefined, it will return null or undefined respectively.

See a live example here.

Dynamically Add Props To A Child Component

If your component has an element nested in it, then it will receive a children prop. There are a number of things you can do beyond simply including the children as part of the rendered output of the component. One thing you can do is put additional props on the child.

const ParentWithClick = ({ children }) => {
  return (
    <children.type
      {...children.props}
      onClick={() => alert("You clicked me!")}
    />
  );
};

This ParentWithClick component will reconstitute its child component with its given props and a new onClick prop.

Here is how it can be used:

const App = () => {
  return (
    <ParentWithClick>
      <span>Hello!</span>
    </ParentWithClick>
  );
};

Click on Hello! and you’ll see the alert.

Minor caveat: multiple children and a string child will need to be handled differently.

See a live example here.

Who Is Your Favorite Child?

When we put some content inside the open and close tags of one of our components, we get access to it as the children prop.

const Parent = ({children}) => {
  return (
    <React.Fragment>
      <p>These are my favorites:</p>
      {children}
    </React.Fragment>
  );
}

const App = () => (
  <div>
    <Parent>
      Greg and Marsha
    </Parent>
  </div>
);

What happens if we also provide an explicit children prop to Parent?

const App = () => (
  <div>
    <Parent children={"Jan and Peter"}>
      Greg and Marsha
    </Parent>
  </div>
);

Which will take precedence when we destructure children in the parent component?

In the example above, we’ll still see Greg and Marsha rendered. The content placed inside the tags will take precedence over the explicit children prop.

See a live example here.

React Router Route can call a render function

In General, the React Router Route component looks like this.

<React path="/triangles" component={Triangles} />

If the current url matches /triangles then the Triangles component will render.

If you want to render something simple however, you can pass down a function with the render prop.

<React path="/helloworld" render={this.renderHelloWorld} />

With that function defined in the same parent component and returning some jsx

renderHelloWorld = () => {
  return (
    <div>Hello World!</div>
  )
}

React Anti-Pattern: defaultValue

The use of defaultValue isn’t strictly an anti-pattern, as with everything it’s context dependent. In the context of a small one form react component doing something simple I’d say defaultValue is fine. This is React in-the-small.

React in-the-large or in-the-massive is different. In large applications things change in unforseen ways. In large applications there are explicit or implicit frameworks that are upstream from your component and will affect the operation of your component. React-in-the-large will create multiple entry points to your component. Sometimes its history.push and sometimes its good ol’ Page Refresh. The state of your application will be different in both those cases.

In software that can change in many ways, defaultValue is brittle. Once rendered, an input with defaultValue is completely out of React’s hands. The value of the input cannot be changed when new information becomes available. You can change the value of the input with DOM functions, but then you’re not using React.

Outside of using a React form abstraction value is much more adaptable than defaultValue. It’s more work to setup and maybe harder to get right initially, but far more likely to suit your needs down the road.

Use withRouter To Pass Down React-Router History

A standard way to navigate with react-router besides using the Link component is to call history.push. Components that are directly rendered by a Route will have access to this and other router props. But what about other components?

The withRouter HOC gives us direct access to a history prop.

import React from 'react';
import { withRouter } from 'react-router';

const SpecialButton = withRouter(({ history, path, text }) => {
  return (
    <Button
      onClick={() => { history.push(path); }}
    >
      {text}
    </Button>
  )
});

This special button component is given the history prop via the withRouter HOC along with any props that we directly pass it. With that we are able to directly invoke a route change using history.push().

Read Only Input Elements With React

Here is an input element with a value and no onChange handler.

const MyInput = ({ value }) => {
  return (
    <input value={value} />
  );
};

React will raise a warning regarding the input element because it has a value without an onChange handler leaving React to wonder if it is intended to be a controlled or uncontrolled component.

If our intention is to have the value set but not allow the user to directly change it, we just need to let React know that.

const MyInput = ({ value }) => {
  return (
    <input readOnly value={value} />
  );
};

The readOnly prop means we don’t intend for the input to be modified by user input. The React warning will now go away.

h/t Dillon Hafer

Destructure Variables As Props To A Component

When passing down props, a redundant-feeling pattern can sometimes emerge.

const MyComponent = ({ handleChange, handleBlur }) => {
  return (
    <div>
      <OtherComponent />
      <MySubComponent handleChange={handleChange} handleBlur={handleBlur} />
    </div>
  )
};

The typing feel duplicative, as if there ought to be a better way. One option is to simply pass down all the props:

<MySubComponent {...props} />

This approach may result in passing down props that we don’t intend to pass down and clutters the flow of data in our app.

Here is another approach:

const MyComponent = ({ handleChange, handleBlur }) => {
  return (
    <div>
      <OtherComponent />
      <MySubComponent {...{handleChange, handleBlur}} />
    </div>
  )
};

Here we are taking advantage of two ES6 features. Since the naming is the same, we can use property shorthands. Then we immediately use the spread operator to splat it back out as the props to the component.

h/t Vidal Ekechukwu

Alter The Display Name Of A React Component

Components adopt their display name from the class or function that renders them. A component’s display name becomes important to know about as soon as you start digging through the React devtools interface — whether debugging or just perusing the component hierarchy, the display names of components is what you’ll see. In most circumstances, the display name is good enough as is. If you want or need to, you can change it.

const Hello = ({ name }) => {
  return (
    <h1>{name}</h1>
  );
};
Hello.displayName = "Hola";

By setting the displayName property on this component, you are able to alter what name is used by React devtools.

This can be useful when bringing in a 3rd party library or component that doesn’t use a display name that you find helpful — in particular when using Higher Order Components.

Visually Select A React Element For Inspection

Similar to the Elements tab of Chrome devtools, the React devtools extension provides a visual element selector to make it easier to inspect an element you can see in the browser.

select and inspect a react component

Open the React devtools, click the crosshair icon, hover around the browser until the element you are looking for is visually highlighted, and then click. The React component hierarchy will be expanded to reveal that element. You can now inspect it or quickly navigate to nearby elements.

Defining State In A Simple Class Component

Most class components start off with a constructor which does some initialization of the component including setting the components initial state. It might look something like the following:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: true
    };
  }

  render() {
    if (this.state.loading) {
      return (
        <p>Loading...</p>
      );
    } else {
      // ...
    }
  }
}

If setting state is the only thing you need to do in the constructor, then you can skip the constructor all together.

class MyComponent extends React.Component {
  state = {
    loading: true
  };

  render() {
    if (this.state.loading) {
      return (
        <p>Loading...</p>
      );
    } else {
      // ...
    }
  }
}

This second example will work the same as the first, and it is a bit more concise.

Use A Ref To Autofocus An Input

When creating highly interactive interfaces with React, we are trying to make the user’s experience of our app as smooth as possible. This means that when an edit button reveals an input field, we want that field to be in focus so that the user can immediately start typing.

This is a great use for React’s ref prop. When you supply your component with a function as the ref prop, that function will be called with a reference to itself on mount and with null on unmount.

class MyAutofocusInput extends React.Component {
  focusInput = (component) => {
    if (component) {
      component.focus();
    }
  };

  render() {
    return (
      <input
        ref={this.focusInput}
        value={this.props.value}
        onChange={this.props.onChange}
      />
    );
  }
}

When this component gets rendered, the input will be focused via our focusInput function.

Note: refs only work with class components, so don’t try to use it with a functional component.

See Refs and the DOM in React’s documentation for more details.

Quickly Search For A Component With React DevTools

As the size of your React app grows, it can become challenging to track down specific components within the React DevTools extension. You opened it up with the hopes of quickly inspecting the props being received by a component, but find yourself navigating through the DOM structure instead.

The React DevTools extension provides a search bar that can be used to quickly filter out most components.

react devtools component search

The search bar is located at the top of the extension. Once you start typing the results are immediate. Then, if you hover over any of the remaining components, you’ll get some visual feedback as they are highlighted in the browser.

Dispatch Anywhere With Redux

Your React app is going to have a single top-level store which is connected to the app with the Provider component. Most of the time, when you create a connected component, you’ll create prop functions that dispatch on a redux action.

This isn’t the only place you can dispatch though.

If you export your store, then it can be imported anywhere along with its dispatch function.

// src/index.js
export const store = createStore(rootReducer);
// src/components/MyComponent.js
import { store } from '../index';
import { updateData } from '../actions';

// ...

  componentDidMount() {
    getData().then((json) => {
      store.dispatch(updateData(json));
    }
  }

See the dispatch documentation for more details.

Inactive And Active Component Styles With Radium

Radium is “toolchain for React component styling” allowing you to do comprehensive inline styling with CSS.

Often times, especially in the case of a series of nav elements, there is a need to style one element as active while styling the rest as inactive. This can be achieved with Radium by defining two groups of styles (base and active) and then relying on props to conditionally apply the active style.

import React from 'react';
import Radium from 'radium';

const styles = {
  base: {
    textDecoration: "none",
    color: "gray",
  },
  active: {
    color: "black",
    backgroundColor: "lightgray",
  },
};

let NavItem = ({ label, path, active }) => {
  return (
    <a
      href={path}
      style={[
        styles.base,
        styles[active && 'active'],
      ]}
    >{label}</a>
  );
};

NavItem = Radium(NavItem);

With Radium, our base (inactive) styles always get applied. Then, the active styles only get applied when the active prop is true. We produce a Radium-ified version of our NavItem on the last line so that Radium can handle all of the styling of the component.

Rendering Multiple Nodes With Fragments

When rendering, React expects a component to only return a single node. The DOM hierarchy of most components will easily follow this rule, but what about those components that do have multiple inline nodes?

The two solutions have been to either wrap the inline nodes in an outer div or to return them as a comma separated array of nodes. With React 16, we can avoid the deficiencies of both of these approaches by using a fragment.

Just wrap your inline nodes with a React.Fragment node. React will understand your JSX without wrapping the output DOM in a superfluous div.

render() {
  // ... more code

  return (
    <React.Fragment>
      <p>Name: {firstName} {lastName}</p>
      <p>Email: {email}</p>
      <p>Age: {age}</p>
    </React.Fragment>
  );
}

See the docs on fragments for more details.

Accessing Env Vars In create-react-app

Environment-specific configurations are an important part of most applications. You can access environment variables in your create-react-app code using process.env.

There are a couple built-in environment variables, such as NODE_ENV. Anything custom that you want to provide must be prepended with REACT_APP_. If it isn’t, that environment variable will be ignored with no warning.

The following line of code

const base_api_url = process.env.REACT_APP_BASE_API_URL;

will have access to whatever that value is in the environment when the server is started or the app is built.

Set that value inline like so:

REACT_APP_BASE_API_URL="https://api.my_app.com" yarn start

source

glamorous composition for inline styling

glamorous is a library to help style components from the component itself rather than from a css stylesheet. You create a component with style in the form of a javascript object.

require glam import 'glamorours';

const InfoSpan = glam.span({
  backgroundColor: 'none',
  width: '20%',
  margin: '0 1rem',
  padding: '0 1rem',
  display: 'inline-block',
  boxSizing: 'borderBox'
});

Later when rendering, you can use this as if it were a component.

render() {
  return (
    <div>
      <InfoSpan>
        Some Important Information
      </InfoSpan>
    </div>
  );
}

You can also compose additional glamorous components by re-using previously declared glamorous components.

const LeftSpan = glamorous(InfoSpan, {
  textAlign: 'right'
});

const RedArticle = glamorous(Article, {
  textAlign: 'left'
});

Catchall in a React Router Switch

Today we built a 404 page for a React app using React Router, via a Switch statement with no specified path. Like a default clause, it catches if none of the other routes match:

<Switch>
  <Route path="/about" component={About}/>
  <Route component={NoMatch}/>
</Switch>

On any other path besides /about, we’ll render our NoMatch component.

Custom Browser with Create React App

Sometimes Google Chrome isn’t your default browser for surfing the internet, but it is your default browser during development. With create-react-app you can specify an alternate browser to automatically open (or no browser at all), to avoid opening the wrong development browser all the time.

Just pre-pend the browser to the start script:

{
  "name": "custom-browser",
  "version": "0.1.0",
  ...
  
  "scripts": {
    "start": "BROWSER='Google Chrome' react-scripts start",
    ...
  }
}

Proxy To An API Server In Development With CRA

create-react-app is a great way to bootstrap a React project, especially if you are building a single-page app. When building an SPA, you more likely than not will have a backend API that you interact with.

You can set up your React app to interact with that backend API server in development using the proxy configuration in package.json.

// package.json
  ...
  "proxy": "http://localhost:4000",
}

This will allow you to keep your API calls nice and clean.

fetch("/api/session", ...

No need to manage some sort of host URL environment variable.

Additionally, this will remove an CORS issues because the webpackDevServer will be proxying any paths that it doesn’t recognize to the host and port that you’ve specified.

See the create-react-app docs for more details.

Legacy Refs vs Ref Callbacks

Reactjs provides a way to get references to dom elements that react is rendering through jsx. Previously, it was through what are now legacy refs:

componentWillUpdate() {
  this.refs.thing.tagName == "div";
}

render() {
  return (
    <div ref="thing"/>
  );
}

Where you can assign an element an identifier and react would keep a refs hash up to date with references to the dom for that element.

The react docs say this about the previous system.

We advise against it because string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases.

The new system uses callbacks

render() {
  return (
    <div ref={(div) => { console.log('tag name:', div.tagName); }} />
  );
}

This callback is called when the component mounts with a reference to the dom element as an argument. Importantly, when the component unmounts the callback is called again but this time with null as an argument.

.babelrc ignores babel settings in package.json

There are three ways to provide babel configuration listed on the usage page for babelrc. You can provide a .babelrc file, you can place a babel section in your package.json or you can declare configuration with an env option.

If you have both a .babelrc in your root dir AND a babel section in your package.json file then the settings in the package.json will be completely ignored.

This happened to me when needing to declare an extra plugin for babel that create-react-app did not provide. I ejected from create-react-app, I added a .babelrc that declared the extra plugin, and this broke the build for my app. The babel configuration for an ejected create-react-app is in the package.json file.

Inline Style Attributes Should Be Camel Cased

When adding a few quick styles to React components, you can add it directly on the tags in the JSX. To do this, use the style tag with a plain old JavaScript object of styles.

<div style={{ padding: "1em", color: "#fff" }}>

If you are using a CSS attribute that is normally hyphenated like padding-top or background-color, you’ll need to camel case it in the JSX.

<div style={{ paddingTop: "1em", backgroundColor: "#fff" }}>

This is because our styles now need to conform to JavaScript syntax rules since they are in the form of a POJO.

Read the documentation for more details.

Passing Props Down To React-Router Route

When using react-router, you’ll often use the component prop to have a certain component rendered.

<Route
  path="/my/path"
  component={MyComponent}
/>

If, however, you need to pass props down into MyComponent, then you’ll want to use the render prop with an inline function.

<Route
  path="/my/path"
  render={(routeProps) => (
    <MyComponent {...routeProps} {...props} />
  )}
/>

The two spread operator statements are essential. They will pass down the route props that Route would have passed down plus the additional set of props that you want to pass down.

Force A Component To Only Have One Child

A component can normally have an arbitrary number of elements nested directly inside it. React’s Children.only function can be used to force it to a single direct child.

import React, { Children, Component } from "react";

class App extends Component {
  render() {
    return (
      <SingleChildContainer>
        <span>There can only be one!</span>
      </SingleChildContainer>
    );
  }
}

const SingleChildContainer = props => {
  return Children.only(props.children);
};

export default App;

The React docs describe the behavior of Children.only as such, “Returns the only child in children. Throws otherwise.”.

If you modify the return in App to contain the following JSX

<SingleChildContainer>
  <span>There can only be one!</span>
  <div>What about me?!</div>
</SingleChildContainer>

then an error will be thrown (React.Children.only expected to receive a single React element child).

The Provider component in react-redux is an example of where this is used.

Render An Array Of Elements With React 16

React 16 was released today. Among many exciting features and updates is support for rendering an array of elements.

This can look as simple as this example:

return [
  <li key="1">One</li>,
  <li key="2">Two</li>,
  <li key="3">Three</li>
];

It really shines in the case of generating elements from an array of data.

let data = [
  { value: "One", key: "1" },
  { value: "Two", key: "2" },
  { value: "Three", key: "3" }
];
return data.map(item => {
  return (
    <li key={item.key}>
      {item.value}
    </li>
  );
});

No need to wrap the result in a <div>!

source

Export a synchronous method in React Native module

If you are working with an existing brownfield iOS app you may already have some code that is really complicated to change and sometimes you want a bridge module to export some native methods to JS that return synchronous values right way. In iOS, you can use the macro RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD:

@define API_URL @"http://localhost:3000"

@implementation ConfigManager

RCT_EXPORT_MODULE();

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getApiUrl) {
  return API_URL;
}

@end

And in your JS file you can call:

import { NativeModules } from 'react-native';

const apiUrl = NativeModules.ConfigManager.getApiUrl();

There is a problem using that when your app is in debug mode. It will raise the error global.nativeCallSyncHook is not a function. Also this macro blocks the current thread, so only use it if you REALLY need it.

Handle JS Errors in React 16

React 16 introduced a new method called componentDidCatch to catch all JS errors. It can catch errors during rendering, lifecycle methods and constructors of the whole tree below.

class App extends React.Component {

  componentDidCatch(error, info) {
    ErrorService.log(error, info);
  }

  render() {
     // code that raises error, it could come from this component or its children.
  }
}

Invisible components in React Native

Sometimes you want a component to be rendered but not visible to the user and in React Native 0.42 and below, you could accomplish that by setting the component’s height and width to 0.

The good news is that React Native 0.43 will make it easier and introduce the CSS property you are already familiar with: display: 'none'.

You can already try it installing the pre-release version 0.43.0-rc.4.

React wrapper components with nested children

Say you want to create a component that acts as a wrapper such that you can pass it nested child components like so:

<WrapperComponent title="I am the wrapper">
  <ChildComponent body="Hello from child component" />
</WrapperComponent>

This can be achieved by using this.props.children as in this example:

class WrapperComponent extends Component {
  render() {
    return (
      <div className="wrapper">
        <h1>{this.props.title}</h1>
        {this.props.children}
      </div>
    );
  }
}

class ChildComponent extends Component {
  render() {
    return (
      <p>{this.props.body}</p>
    );
  }
}

class App extends Component {
  render() {
    return (
      <WrapperComponent title="I am the wrapper">
        <ChildComponent body="Hello from child component" />
      </WrapperComponent>
    );
  }
}

Mounting App will produce the following markup:

<div class="wrapper">
  <h1>I am the wrapper</h1>
  <p>Hello from child component</p>
</div>

TouchableHighlight with custom component

Usually in React Native when you want to add touch events to a custom component you just wrap it with a Touchable* component.

If you want to use TouchableOpacity there is no need to change anything on the custom component, but if you want to use TouchableHighlight you have to change the component and implement setNativeProps and delegate to the container View:

class CustomComponent extends Component {
  render() {
    return (
      <View ref='container'>
        ...
      </View>
    )
  }

  setNativeProps(nativeProps) {
    this.refs.container.setNativeProps(nativeProps);
  }
}

And then you are ready to go:

<TouchableHighlight onPress={this._onPress} underlayColor="#fc0">
  <CustomComponent />
</TouchableHighlight>