KWeiss
KWeiss

Reputation: 3144

"unscoped" variable in react class module file

I have a component that receives some props. In the same file, I have some helper functions that also use one of the props. I'd like to save the prop value inside a variable in the file.

Is there any reason in terms of functionality or style that I should not do this?

Here's some pseudo code to show what I'm talking about, representing the whole file:

// imports go here

let unscopedVar = null

const myOnBlur = (ev) => {
    console.log(unscopedVar)
    console.log(ev)
}

const MyComponent = (props) => {
    unscopedVar = props.someVar

    return <input onBlur={myOnBlur} />
}

export default MyComponent

The alternative would be to pass more variables to the functions, but I'd like to avoid that. In my real code, more than one function needs the variable, and they each take more than one other parameter:

// imports...

const myOnBlur = (ev, unscopedVar) => {
    console.log(unscopedVar)
    console.log(ev)
}

const MyComponent = (props) => {
    return <input onBlur = {(ev) => myOnBlur(ev, props.someVar)}
}

Upvotes: 0

Views: 221

Answers (2)

JLRishe
JLRishe

Reputation: 101662

Probably the biggest problem with that approach is that there will only ever be one instance of that variable. If there are multiple instances of your component, then they will all be fighting over the value of that variable and messing up each others' data.

So generally you shouldn't try to store values outside of your components.

In terms of alternatives, there are several ways you could go about it:

  1. The approach you described - use a closure to capture the value when the handler is invoked:
const MyComponent = (props) => {
    return <input onBlur = {(ev) => myOnBlur(ev, props.someVar)}
}
  1. Use a class component, in which case the handler can just access this.props:
class MyComponent extends React.Component {
    myOnBlur(ev) {
        console.log(this.props.someVar)
        console.log(ev)
    }

    render() {
        return <input onBlur={this.myOnBlur} />
    }
}
  1. Define your handler inside the MyComponent function, so that it has access to the same scope:
const MyComponent = (props) => {
    const myOnBlur = (ev) => {
        console.log(props.someVar)
        console.log(ev)
    }

    return <input onBlur={myOnBlur} />
};

If your handler is fairly large and complex, the last option is probably the least ideal because it means a separate copy of the whole handler would be created every time the component is rendered.

Upvotes: 1

Oblosys
Oblosys

Reputation: 15106

This is not a good idea. Your unscopedVar may be equal to props.someVar but this is not clear when looking at it's declaration or use. For a toy example it seems harmless, but as your component grows (as they usually do,) it will be harder to keep track of these relations between props and variables.

Another problem arises if you convert your functional component to a class component, after which you'll need to use lifecycle methods to keep the variable in sync with the prop.

If a lot of helper functions use props, you can just use a class component, and access this.props in the helper functions:

class MyComponent extends React.Component {
  myOnBlur = (ev) => {
    console.log(this.props.someVar)
    console.log(ev)
  }

  render() {
    return <input onBlur={this.myOnBlur} />
  }
}

Upvotes: 1

Related Questions