1

Is it possible to pull class methods out of the class in JS? Forgive me, I am functional paradigm, so using React forces me to use classes and this keyword (so far anyway). Some of my components are getting large and I do not want this.

I can't find anything on Google about pulling methods out or modularizing a class.

Is there a way I can just say "get this method from './some_method.js' and use it as if it was declared inside this file&class" without much invasive changes?

Failing that, I'm hypothesizing about making them all functions and pass this into them. That feels pretty dirty, however.

I'd appreciate some guidance to what keywords I need to be looking at, or simply how to move methods out so I don't have 2000 line files that take me 20 minutes to find

toggleFullMenu() {
    this.setState({ menuOpen: !this.state.menuOpen})
}

without pressing CTRL+F. That is my motivation.

I'd also like to know if there are any pro tips about this as relates to constructors. Any warnings from the class inheritance paradigm folks? I simply want the methods to sit by themselves in separate files, but I don't know what I'm looking for. I've never seen people talking about this.

Edit, I just found this in the MDN:

Sub classing with extends

The extends keyword is used in class declarations or class expressions to create a class as a child of another class.

Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

class Dog extends Animal {
  speak() {
    console.log(this.name + ' barks.');
  }
}

Is this what I need? How would I go about pulling a bunch of extensions in? I don't want a child class though, that doesn't sound like what I am describing.

Community
  • 1
  • 1
agm1984
  • 15,500
  • 6
  • 89
  • 113

3 Answers3

2

You can do so using Function.prototype.bind, so that you have control of the value of this.

In one module, you can export the "method" as a regular function:

// methods.js
export const toggleFullMenu = () => {
  this.setState({ menuOpen: !this.state.menuOpen })
}

And in your component module:

import React from 'react'
import { toggleFullMenu } from './methods'

class SomeComponent extends React.Component {
  constructor () {
    super()
    this.toggleFullMenu = toggleFullMenu.bind(this)
  }

  render () {
    return <button onClick={this.toggleFullMenu}>Click Me</button>
  }
}

The toggleFullMenu function could be bound to other contexts as well, so you could actually share that method across different components.

EDIT: There are many different ways to bind the context of a function, you are not limited to Function.prototype.bind. See this chapter for an explanation of the various ways to do so.

djfdev
  • 5,747
  • 3
  • 19
  • 38
  • This is sounding nice. I can work with concise declarations like that. So inside the main class, I can just call `this.toggleFullMenu({ some, stuff, and, this.morePoop })` and the `this` keyword association will remain intact as if the method was inside the class? – agm1984 Oct 13 '17 at 21:36
  • Is there any way I can use fat arrow instead of `bind(this)` ? Probably not, that probably doesn't make logical sense in this context, but I have to probe. This answer is actually really great. I will research `Function.prototype.bind` later today. – agm1984 Oct 13 '17 at 21:38
  • To answer your first question, the value of `this` inside of an instance method will be the instance of the class itself (however, you should understand the implications of referencing functions vs. calling them ... the value of `this` will be lost when passed by reference, unless explicitly bound as above). – djfdev Oct 13 '17 at 21:42
  • 1
    Second question, I would refer to this article for the various ways to do this type of thing http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html. Basically the answer is yes, and there are a few ways to do this depending on which version of JavaScript you are using. – djfdev Oct 13 '17 at 21:45
  • I am using all newest. I want the 2018 industry standard way to store the methods outside the class. I use try/catch architecture with async/await usually. I am very familiar with JS excluding classes and this aspect of prototypal inheritance, so don't hold back. I really appreciate the keywords you are dropping. I usually write in 100% functions, so maintaining proper reference to `this` should be straight forward, and I am not opposed to creating bound/exotic functions. All I want to do is store the methods in another file. I will handle wild use cases as I encounter them. – agm1984 Oct 13 '17 at 21:48
  • I'm pretty sure I understand what you are saying in your first comment above. I have to test the behaviour a bit with a more complex method to see if any context can get mangled. I try to avoid usage of `this` as much as possible. I only really use it to call methods in the class or refer to state variables. I can usually make dumb components and pass all the data I need into them. – agm1984 Oct 13 '17 at 21:54
  • @djfdev look pretty nice time to try this thing someday – Manjeet Singh Oct 13 '17 at 21:59
  • @agm1984 Here's a quick example I set up to show you the differences between calling a method, referencing a method, and referencing a method that has been explicitly bound https://www.webpackbin.com/bins/-KwMjg--rg1PksrNhgVK – djfdev Oct 13 '17 at 22:15
2

Right ahead I can say that Yes you can pull out different methods from other classes or files other than created in your component. There lots of different ways to go and it really depends on your preference. You can go from really simple to really complex structures.

First thing you need to search and learn about (if you don't already know) require() and/or ES6 import and export. You can create stand alone functions or objects and import them into your component to use them. If you have repeating functions that you use in different components or parts of your app this is the way to go.

If I comment on passing this as a parameter, it is not pretty like you said in your question. Rather than passing this, passing required parameters to functions and using callbacks or Promises is the way to go. Another technique you can use is to bind function to this. ES6 arrow functions don't need to be bind since they don't bind their own this.

If you would like to go a little more complex/complicated you can always create your own classes. Class structure can give ability to do more complex things. extends gives you ability to extend (like you can understand from its name) your class methods with others or overwrite them with new ones. For example, Beverages, Snacks, Meats can be classes that extends from Foods class. When you create a custom component you extend a React.Component and then you use its methods.

Another thing to consider is that having a 2000 lines component makes me think that you should also consider separating your components into smaller chunks. Parent/Child component relationship is most common and supported structure in React. If you use this pattern your code will automatically get smaller and it will be much more easier to follow and manage. There are lots of examples on how to pass functions as props to child components and run them in certain conditions with certain parameters and then manipulating parent component's state. You can look for those examples to get better understanding.

I hope these topics will help you to understand couple of thing and show you to where to start.

bennygenel
  • 23,896
  • 6
  • 65
  • 78
0

Webpack is a fully-featured javascript app bundler. With Webpack you can import / export code like:

export default class CustomerView {
    render() {
        ...
    }
}

and

import CustomerView from './CustomerView'

`

Yoann N
  • 51
  • 3
  • I'm talking about methods inside CustomerView, such as pulling the render method out into a separate file. – agm1984 Oct 13 '17 at 21:29