2

I have a bunch of components with methods like these

class Header extends Component {

  sidebarToggle(e) {
    e.preventDefault();
    document.body.classList.toggle('sidebar-hidden');
  }

  sidebarMinimize(e) {
    e.preventDefault();
    document.body.classList.toggle('sidebar-minimized');
  }
}

I'd like to move this duplicate code to a function such as

function toggleBodyClass(className, e) {
  e.preventDefault();
  document.body.classList.toggle('sidebar-mobile-show');
}

Then refactor the functions above like so

  sidebarMinimize(e) {
    toggleBodyClass('sidebar-minimized', e);
  }

In the past, I would have used a mixin, but the React docs now discourage their use.

Should I just put this function in a regular JavaScript module and import it in the component modules, or is there a particular React construct for reusing code across components?

2
  • A small suggestion: It looks like you are using <a/> links as buttons (Since you're using all those preventDefaults). Maybe just convert them to <button> elements? Then you can leave out those preventDefault calls. Commented Jan 26, 2018 at 13:42
  • @Carl Edwards is correct, the Props Proxy Higher Order Component pattern is what the react docs recommend: reactjs.org/docs/higher-order-components.html some more info: medium.com/@franleplant/… Commented Jan 26, 2018 at 16:16

4 Answers 4

1

You could make a High Order Component with those functions as so:

import React, { Component } from 'react';

export default function(ComposedComponent) {
  return class ExampleHOC extends Component {
    sidebarToggle(e) {
      e.preventDefault();
      document.body.classList.toggle('sidebar-hidden');
    }

    sidebarMinimize(e) {
      e.preventDefault();
      document.body.classList.toggle('sidebar-minimized');
    }

    render()
      return <ComposedComponent { ...this.props } />;
    }
  }  
}

Then take whatever component you wish to augment with those properties by wrapping them in the HOC:

ExampleHOC(Header);
Sign up to request clarification or add additional context in comments.

9 Comments

This doesn't answer OP's question properly. You should read it again.
what you mean it doesn't answer?? that is the React Way! the only problem of the code proposed is that there is not way for the underlying component to access the functionality of the hoc, but it is easy to solve
of course it is settings asign messing about with dom in react is rarely a good idea
@DanielKhoroshko read it again. OP wants to move the logic of changing an element classname and running event.preventDefault to a method to define it once, and then use it to define methods that implement such logic in a DRY way. Your answer is not a proper implementation of this. Also he didn't ask for a 'React way', he asked if he should do it the standard JS way or if there's a better React-specific option for this case. There isn't.
@DanielKhoroshko What am I missing for the original component to access the functionality of the HOC?
|
0

Should I just put this function in a regular JavaScript module and import it in the component modules

Yes. That would be a pretty standard way to share code between JavaScript files. I don't believe you need to or should do anything React-related to achieve this.

However, it is important to understand that you shouldn't directly interact with the DOM ever from a React component. Thanks @ShubhamKhatri for the heads up.

4 Comments

One thing to understand here is that with React you should not directly modify the DOM
@ShubhamKhatri that is true, I'm gonna add it to my answer, however it is still true.
What should I do instead of document.body.classList.toggle to toggle a class?
@Dónal define the classes in your render method. For example: <div className='someclass someotherclass {{ this.props.classXEnabled ? 'class-x' : '' }}></div>. Then the method that you want to expose should toggle this.props.classXEnabled (true / false). This is just one example, but you should delegate the entire DOM rendering and manipulation processes to React to avoid headaches.
0

In my opinion, you are correct in putting the function in a regular JavaScript module and import it in the component modules.

Since a typical answer OOP answer would be to create another class extending React.Component adding that function. Then extend that class so every component you create will have that function but React doesn't want that.

One thing to verify that you are correct is in this pattern I believe.

https://reactjs.org/docs/composition-vs-inheritance.html

Comments

0

inherence solve your problem , create new class that extends Component and extend from your new class to share functionality and reduce the code

class SuperComponent extends Component
{
    sidebarToggle(e) {
        e.preventDefault();
        document.body.classList.toggle('sidebar-hidden');
      }

      sidebarMinimize(e) {
        e.preventDefault();
        document.body.classList.toggle('sidebar-minimized');
      }    
}

---------------------------------------------------------------------

class Home extends SuperComponent
{
    someMethod()
    {
        this.sidebarMinimize();
    }
}

class Main extends SuperComponent
{
    someMethod()
    {
        this.sidebarToggle();
    }
}

Other Solution

create utils class and use it in your component

class UIUtiles
{
    static sidebarToggle(e) {
        e.preventDefault();
        document.body.classList.toggle('sidebar-hidden');
    }

    static sidebarMinimize(e) {
        e.preventDefault();
        document.body.classList.toggle('sidebar-minimized');
    }

}

class Home extends SuperComponent {
    someMethod(e) {
        UIUtiles.sidebarToggle(e);
        UIUtiles.sidebarMinimize(e);
    }
}

2 Comments

I appreciate the answer, but I'd prefer a composition-based solution to one that relies on inheritance.
@Dónal checkout the other solution

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.