React - Why does using a global variable to store this make React see only the last reference?

Asked

Viewed 1,163 times

0

I am learning reactjs and I came across a situation that I need help to understand, and being specific I couldn’t find any reference to it.

I have the file Input.js

import React, { Component } from 'react'
import Input, { InputBootstrap } from 'react-bootstrap'

export default class Input extends Component {
    render() {
        return (
            <div>
                <label htmlFor={this.props.id}>
                    <span>{this.props.label}: </span>
                    <InputBootstrap id={this.props.id} type={this.props.type} name={this.props.name} value={this.props.value} onChange={this.props.onChange} alt={this.props.alt} placeholder={this.props.placeholder} />
                </label>
            </div>
        );
    }
}

In order to create a generic input for my SPA.

And the file Cadastro.js

export default class Cadastro extends Component {
    constructor() {
        super();
        self = this;

        ...
    }

    render() {
        return (
            <div>
                <Input id='nome' type='text' name='nome' label='Nome' value={self.state.nome} onChange={self.setNome} placeholder='Seu nome' alt='Nome do Cliente' />
                <Input id='telefone' type='text' name='telefone' label='Telefone' value={self.state.telefone} onChange={self.setTelefone} placeholder='(11) 1111-1111' alt='Telefone do Cliente' />
                <Input id='dataDeNascimento' type='date' name='dataDeNascimento' label='Data de Nascimento' value={self.state.dataDeNascimento} onChange={self.setDataDeNascimento} placeholder='DD/MM/AAAA' alt='Data de nascimento do Cliente' />
                <Input id='cpf' type='number' name='cpf' label='CPF' value={self.state.cpf} onChange={self.setCPF} placeholder='123.456.789-10' alt='CPF do Cliente'/>
                <Input id='email' type='email' name='email' label='E-mail' value={self.state.email} onChange={self.setEmail} placeholder='[email protected]' alt='Email do Cliente' />
                ...

But I’ve been using a pattern so I don’t have to keep inserting .bind(this) at the end of each method I create, using the self = this;

Following this pattern would look like this file Input.js

import React, { Component } from 'react'

var self;

export default class Input extends Component {
constructor() {
    super();
    self = this;
}

render() {
    return (
        <div>
            <label htmlFor={self.props.id}>
                <span>{self.props.label}: </span>
                <input id={self.props.id} type={self.props.type} name={self.props.name} value={self.props.value} onChange={self.props.onChange} alt={self.props.alt} placeholder={self.props.placeholder} />
            </label>
        </div>
    );
}
}

Using this way the result I have on the screen is not as expected, as soon as I insert the first character in any input screen is as in the image.

Print da tela

I don’t understand why to change all fields to the list I created in the file Cadastro.js

Can you help me, please?

1 answer

1

When you have a file like Input.js this file is read only 1 time. Regardless of how many components (instances) of <Input /> create, that file will only have been read once. So what happens is that this global variable is only read once, and it’s the same for all components, not a new variable per component...

The advantage of using classes is that you can easily have a reference to yourself using the this. To help run functions with the desired execution context you can use Arrow functions (() => {}) that preserve the this within the scope.

This problem of using the .bind(this) was very common in old React, before native classes were used, that is when React used Objects which in practice generated a function with methods that had to be associated via .bind() to the instance.

Modern react with Arrow functions allows to use thus, as in the example onClick below:

class Pessoa extends React.Component {
  constructor() {
      super();
      this.state = {
        mostrarNome: false, 
      };
  }
  render() {
    const nome = this.state.mostrarNome && (<div>{this.props.nome}</div>);
    const button = !this.state.mostrarNome && (<button onClick={() => this.setState({mostrarNome: true})}>Quem sou eu?</button>);
    return (
      <div>
        {nome}
        {button}
      </div>
    );
  }
}

ReactDOM.render(
  <div>
    <Pessoa nome="Maria" />
    <Pessoa nome="Antonio" />
  </div>,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="react"></div>

  • Got it! Thanks for the reply!

  • @Danilloparreira if the answer solved your problem can click to mark as accepted.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.