Tylerlee12 Tylerlee12 - 2 months ago 8
React JSX Question

Click event improperly changing all React components of the same type

I have an

onClick
event set up for a component that is rendered multiple times. When this onClick is triggered, text inside a button determined by a JS variable is changed. However, when I click a button for one component the text changes for all other components of this same type. Here is the code:

FormEntity.js:

import React from 'react';

let hasFile = false;
let uploadBtnText = 'Simulate file upload';
const FormEntity = (props) => {
const handleClick = () => {
if(hasFile) {
props.formInstanceRemoved(props.instanceId);
hasFile = false;
uploadBtnText = 'Simulate file upload';
} else {
props.formInstanceUploaded(props.instanceId, props.blueprintId);
hasFile = true;
uploadBtnText = 'Remove file';
}
};

return (
<div>
<button type="button" onClick={handleClick}> {uploadBtnText} </button>
</div>
);
};

export default FormEntity;


Here is a picture that should help further show the problem.

enter image description here

Clicking a button should only effect the text and whatever else is within that button, not all the other components too. Any advice?

Answer

You want each button to have its own state, so you should define the buttons as stateful ones and use setState. Your current implementation changes module-level variables, which are shared by all instances of the button.

const FormEntity extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      hasFile: false,
      uploadBtnText: 'Simulate file upload',
    };
  }

  handleClick = () => {
    if (this.state.hasFile) {
      this.props.formInstanceRemoved(props.instanceId);
      this.setState({
        hasFile: false,
        uploadBtnText: 'Simulate file upload',
      });
    } else {
      this.props.formInstanceUploaded(props.instanceId, props.blueprintId);
      this.setState({
        hasFile: true,
        uploadBtnText: 'Remove file',
      });
    }
  };

  render() {
    return (
      <div>
        <button type="button" onClick={this.handleClick}> {uploadBtnText} </button>
      </div>
    );
  }
};