David Yeiser
David Yeiser

Reputation: 1578

Move function in React from component to referenced library

I'm learning React and I'm not sure how to setup this pattern. It could be something really easy I'm just missing.

I have a main component that controls state. It has all of the functions to update state and passes these down to child components via props. I've simplified the code to focus on one of these functions.

Here's the component now, all works as it should:

ManageMenu.js

import React from 'react'

class ManageMenu extends React.Component {
  constructor() {
    super()

    this.toggleEditing = this.toggleEditing.bind(this)

    // Set initial state
    this.state = {
      menuSections: []
    }
  }

  toggleEditing(id) {
    const menuSections = this.state.menuSections

    menuSections.map(key => (key.id === id ? key.details.editing = id : ''))

    this.setState({ menuSections })
  }

  render() {
    return (
      ...
    )
  }
}

export default ManageMenu

The toggleEditing is passed via props to a child component that uses it to render an editing form if the edit button is clicked.

I have about 10 of these different functions in this component and what I would like to do is move them to an external lib/methods.js file and then reference them. Below is the code I would like to have, or something similar, but React doesn't like what I'm doing. Throws a syntax error:

Failed to compile.
Error in ./src/components/ManageMenu.js
Syntax error: Unexpected token
toggleEditing(id, menuSectionId, this.state, this)

Here is what I would like to do...

lib/methods.js

const toggleEditing = function(id, state, that) {
  const menuSections = state.menuSections

  menuSections.map(key => (key.id === id ? key.details.editing = id : ''))

  that.setState({ menuSections })
}

module.exports = {
  toggleEditing
}

And then in my component:

ManageMenu.js

import React from 'react'
import { toggleEditing } from '../lib/methods'

class ManageMenu extends React.Component {
  constructor() {
    super()

    // Set initial state
    this.state = {
      menuSections: []
    }
  }

  toggleEditing(id, this.state, this)

  render() {
    return (
      ...
    )
  }
}

export default ManageMenu

Any help is appreciated, thanks!

Upvotes: 3

Views: 2900

Answers (2)

David Yeiser
David Yeiser

Reputation: 1578

Thanks to @Nocebo, the answer on how to externalize functions is here: Externalise common functions in various react components

In my particular situation,

  1. I need to remove the “floating” toggleEditing(id, this.state, this) call in the middle of nowhere. Update: This error happens “because it is invoking a method within a class definition.” (see Pineda’s comment below)
  2. Remove the leading this. on the right side of the this.toggleEditing statement in constructor()
  3. Update the function in lib/methods.js to remove the state and that variables since its bound to this in the constructor()

See updated code below.

ManageMenu.js

import React from 'react'
import { toggleEditing } from '../lib/methods'

class ManageMenu extends React.Component {
  constructor() {
    super()

    this.toggleEditing = toggleEditing.bind(this)

    // Set initial state
    this.state = {
      menuSections: []
    }
  }

  render() {
    return (
      ...
    )
  }
}

export default ManageMenu

lib/methods.js

const toggleEditing = function(id) {
  const menuSections = this.state.menuSections

  menuSections.map(key => (key.id === id ? key.details.editing = id : ''))

  this.setState({ menuSections })
}

module.exports = {
  toggleEditing
}

Upvotes: 2

Pineda
Pineda

Reputation: 7593

You're error arises because you are invoking toggleEditing in your ManageMenu.js class definition rather than defining a function.

You can achive what you want by setting a local class member this.toggleEditing to the bound function returned by the .bind method and do so within the constructor:

import React from 'react'
import { toggleEditing } from '../lib/methods'

class ManageMenu extends React.Component {
  constructor() {
    super()    
    this.state = {
      menuSections: []
    }

    // bind external function to local instance here here
    this.toggleEditing = toggleEditing.bind(this);
  }

  // don't invoke it here, bind it in constructor
  //toggleEditing(id, this.state, this)

  render() {
    return (
      ...
    )
  }
}

export default ManageMenu

Upvotes: 1

Related Questions