128

I have multiple components which all need to do the same thing. (A simple function which maps over their child components and does something to each one). At the moment I am defining this method in each of the components. But I only want to define it once.

I could define it in the top level component and then pass it down as a prop. But that doesn't feel quite right. It is more a library function than a prop. (It seems to me).

What is the correct way of doing this?

  • Check out [this link](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750). Or search for "mixins" and "HOC" in google. – Borzh Mar 14 '19 at 00:27
  • 1
    Great question. For a newbie like me this has been a gold mine of information :) – NobleGuy Jan 17 '23 at 09:49

8 Answers8

102

Utils.js with latest Javascript ES6 syntax

Create the Utils.js file like this with multiple functions, etc

const someCommonValues = ['common', 'values'];
    
export const doSomethingWithInput = (theInput) => {
   //Do something with the input
   return theInput;
};
    
export const justAnAlert = () => {
   alert('hello');
};

Then in your components that you want to use the util functions, import the specific functions that are needed. You don't have to import everything

import {doSomethingWithInput, justAnAlert} from './path/to/Utils.js'

And then use these functions within the component like this:

justAnAlert();
<p>{doSomethingWithInput('hello')}</p>
Fangming
  • 24,551
  • 6
  • 100
  • 90
47

If you use something like browserify then you can have an external file i.e util.js that exports some utility functions.

var doSomething = function(num) {
 return num + 1;
}

exports.doSomething = doSomething;

Then require it as needed

var doSomething = require('./util.js').doSomething;
deowk
  • 4,280
  • 1
  • 25
  • 34
19

If you want to manipulate state in helper functions follow this:

  1. Create a Helpers.js file:

export function myFunc(){ return this.state.name; //define it according to your needs }

  1. Import helper function in your component file:

    import {myFunc} from 'path-to/Helpers.js'

  2. In your constructor add that helper function to the class

    constructor(){ super() this.myFunc = myFunc.bind(this) }

  3. In your render function use it:

    `render(){

    {this.myFunc()} }`
Carmageddon
  • 2,627
  • 4
  • 36
  • 56
Jaskaran Singh
  • 914
  • 8
  • 8
12

Here are some examples on how you can reuse a function (FetchUtil.handleError) in a React component (App).

Solution 1: Using CommonJS module syntax

module.exports = {
  handleError: function(response) {
    if (!response.ok) throw new Error(response.statusText);
    return response;
  },
};

Solution 2: Using "createClass" (React v16)

util/FetchUtil.js

const createReactClass = require('create-react-class');

const FetchUtil = createReactClass({
  statics: {
    handleError: function(response) {
      if (!response.ok) throw new Error(response.statusText);
      return response;
    },
  },
  render() {
  },
});

export default FetchUtil;

Note: If you are using React v15.4 (or below) you need to import createClass as follows:

import React from 'react';
const FetchUtil = React.createClass({});

Source: https://reactjs.org/blog/2017/04/07/react-v15.5.0.html#migrating-from-reactcreateclass

Component (which reuses FetchUtil)

components/App.jsx

import Categories from './Categories.jsx';
import FetchUtil from '../utils/FetchUtil';
import Grid from 'material-ui/Grid';
import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {categories: []};
  }

  componentWillMount() {
    window
      .fetch('/rest/service/v1/categories')
      .then(FetchUtil.handleError)
      .then(response => response.json())
      .then(categories => this.setState({...this.state, categories}));
  }

  render() {
    return (
      <Grid container={true} spacing={16}>
        <Grid item={true} xs={12}>
          <Categories categories={this.state.categories} />
        </Grid>
      </Grid>
    );
  }
}

export default App;
Benny Code
  • 51,456
  • 28
  • 233
  • 198
  • 1
    Solution one is quite good, I used the same thing in ExpressJS – Hidayt Rahman May 09 '21 at 11:46
  • 1
    Thanks for Solution 2! It solved an issue I was having (I'm new to React) where the Utility function wasn't being recognised. I was trying to call it using this.Utility.HandleError(...) rather than simply Utility.HandleError(...) without the "this". – NobleGuy Jan 17 '23 at 09:31
8

I'll show two styles below, and you'll want to choose depending on how much the components' logic relate to each other.

Style 1 - Relatively related components can be created with callback references, like this, in ./components/App.js...

<SomeItem
    ref={(instance) => {this.childA = instance}}
/>

<SomeOtherItem
    ref={(instance) => {this.childB = instance}}
/>

And then you can use shared functions between them like this...

this.childA.investigateComponent(this.childB);  // call childA function with childB as arg
this.childB.makeNotesOnComponent(this.childA);  // call childB function with childA as arg

Style 2 - Util-type components can be created like this, in ./utils/time.js...

export const getTimeDifference = function (start, end) {
    // return difference between start and end
}

And then they can be used like this, in ./components/App.js...

import React from 'react';
import {getTimeDifference} from './utils/time.js';

export default class App extends React.Component {
    someFunction() {
        console.log(getTimeDifference("19:00:00", "20:00:00"));
    }
}

Which to use?

If the logic is relatively-related (they only get used together in the same app), then you should share states between components. But if your logic is distantly-related (i.e., math util, text-formatting util), then you should make and import util class functions.

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
7

Another solid option other than creating a util file would be to use a higher order component to create a withComponentMapper() wrapper. This component would take in a component as a parameter and return it back with the componentMapper() function passed down as a prop.

This is considered a good practice in React. You can find out how to do so in detail here.

Jake
  • 990
  • 1
  • 10
  • 17
4

Sounds like a utility function, in that case why not put it in a separate static utility module?

Otherwise if using a transpiler like Babel you can make use of es7's static methods:

class MyComponent extends React.Component {
  static someMethod() { ...

Or else if you are using React.createClass you can use the statics object:

var MyComponent = React.createClass({
  statics: {
    customMethod: function(foo) {
      return foo === 'bar';
    }
  }

However I don't advise those options, it doesn't make sense to include a component for a utility method.

Also you shouldn't be passing a method down through all your components as a prop it will tightly couple them and make refactoring more painful. I advise a plain old utility module.

The other option is to use a mixin to extend the class, but I don't recommend that as you can't do it in es6+ (and I don't see the benefit in this case).

Dominic
  • 62,658
  • 20
  • 139
  • 163
  • The information about mixins is useful. In this case I want to conditionally use the function rather than have something happen automatically on a lifecycle event. So. As you say a plain old utility function is the way to go. –  Oct 16 '15 at 11:10
  • 1
    Note: ``React.createClass`` is deprecated since React 15.5.0. create-react-app suggests use of the npm module ``create-react-class`` instead. – Alex Johnson Sep 19 '17 at 16:56
  • I'm looking to do the same thing as the OP but I'm a bit confused here. You don't recommend any of the options you list. What **do** you recommend? – kkuilla Apr 11 '18 at 10:30
  • I would simply make a file for the function e.g. `doSomething.js`, or a file with multiple similar "utility" functions e.g. `utils.js` and import those functions where you need to use them – Dominic Apr 11 '18 at 11:52
2

Shouldn't you use a Mixin for this ? See https://facebook.github.io/react/docs/reusable-components.html

Although they are falling out of favour see https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750

Might be useful

Davet
  • 334
  • 1
  • 3
  • 15
  • I agree that mixin is a better solution here than just exporting a common function. – Tao Huang May 06 '16 at 22:27
  • @TaoHuang Some things to consider, 1.Mixins are not future proof and will get used less and less in modern apps, 2.Using an exported function makes your code framework agnostic - you could easily use those function on any other js project. Also please read this post about why NOT to use Mixins --> https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html – deowk Aug 29 '16 at 15:25
  • A mixin may access and modify state, while a trait does not, and since the OP is saying they want something to treat as a function library, a mixin would not be the right solution. – HoldOffHunger Jul 31 '17 at 18:45
  • To update this , use higher order functions . https://facebook.github.io/react/docs/higher-order-components.html – Davet Aug 01 '17 at 16:43
  • First link is dead – alex Jul 20 '20 at 09:10