0

Im using react and displaying some labels via the array object of labels. Now, I want to do this dynamically. So if a user clicks a button, the object updates and the user interface should update accordingly as well. The issue here is that I got the array to update after clicking on the button, as evidenced by a console log line that I wrote in the onclick handler. But the user interface does not update accordingly. Just the array shows the values. Here is what the inital array looks like:

const labelsArray = [
  { label: 'Hey There', sublabel1: 'How are you?' },
  {
    label: 'Greetings', sublabel1: 'Fellows'
  },
  { label: 'Awesome', sublabel1: 'Youre doing great', sublabel2: 'cool' }
];

I want to append a warningLabel, and errorLabel to the 2nd object of this array. So since arrays are 0 indexed, I did the following in the onclick handler:

const appendLabel = async () => {
  labelsArray[1].warningLabel = "Hello";
  labelsArray[1].errorLabel = "Hello";
  console.log(labelsArray)
};

The array updates, but not the user interface. Which is really weird.

enter image description here

Also, this is not related to react state mutation, which I know because of my research of this topic when I was trying to figure it out. So just to be clear, its not about state mutation, which might have someone put this as a duplicate question. Its more of a react/object structure question. But I could be wrong! Anyways, any help is appreciated. Thanks!

Here is my whole component for reference

import React, { useState } from 'react';
import { Button, Typography } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles/';
import Stepper from '@material-ui/core/Stepper';
import Step from '@material-ui/core/Step';
import StepLabel from '@material-ui/core/StepLabel';
import StepConnector from '@material-ui/core/StepConnector';
import PropTypes from 'prop-types';


const styles = theme => ({
  stepLabelRoot: {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center'
  },
  checklistHeader: {
    fontWeight: 'bold',
    marginTop: '80px'
  },
  connectorIcon: {
    color: theme.palette.text.secondary
  },
  stepper: {
    background: 'none',
    fontWeight: 'bold'
  },
  checkListImageContainer: {
    display: 'flex',
    flexDirection: 'row',
    alignItems: 'center'
  },
  connector: {

  },
  activeConnector: {
    border: 'solid 1px #6fef71'
  },
  stepIcon: {
    height: '35px',
    width: '35px',
    '&:hover': {
      backgroundColor: 'rgba(134, 141, 150, 0.37)',
      borderRadius: '50%'
    },
  },
  activeStepIcon: {
    backgroundColor: 'yellow'
  },
  label: {
    fontWeight: 'bold',
    display: 'flex',
    fontSize: '15px'
  },
  sublabel: {
    fontWeight: 'normal',
    fontSize: '13px'
  },
  errorLabel: {
    color: 'red'
  },
  warningLabel: {
    color: 'yellow'
  },
  step: {
    '&$completed': {
      color: 'lightgreen'
    },
    '&$active': {
      color: 'pink'
    },
    '&$disabled': {
      color: 'red'
    },
  },
  alternativeLabel: {},
  active: {

  }, // needed so that the &$active tag works
  completed: {

  },
  disabled: {

  },
  labelContainer: {
    '&$alternativeLabel': {
      marginTop: 0
    },
  },
});

const labelsArray = [
  { label: 'Random text?', sublabel1: 'Lorem Ipsum' },
  {
    label: 'Another random text', sublabel1: 'Hello World'
  },
  { label: 'Cool', sublabel1: 'cool', sublabel2: 'ayo' }
];


const Checklist = ({ classes,activeStep }) => {

  return (
    <React.Fragment>
      <Stepper alternativeLabel activeStep={2} connector={<StepConnector />} className={classes.stepper}>
        {labelsArray.map(label => (
          <Step key={label} completed>
            <StepLabel active
              completed
              StepIconProps={{
                classes: {
                  root: classes.step,
                  completed: classes.completed,
                  active: classes.active,
                  disabled: classes.disabled
                }
              }}>
              <div className={classes.stepLabelRoot}>
                <span className={classes.label}>
                  {label.label}
                </span>
                <span className={classes.sublabel}>
                  {label.sublabel1}
                </span>
                <span className={classes.sublabel}>
                  {label.sublabel2}
                </span>
                <span className={classes.sublabel}>
                  {label.sublabel3}
                </span>
                <span className={classes.errorLabel}>
                  {label.errorLabel && <img src="/static/images/lock-material.png" alt="img" style={{ height: '15px', width: '15px' }} />}
                  {label.errorLabel}
                </span>
                <span className={classes.warningLabel}>
                  {label.warningLabel && <img src="/static/images/warning-sign.png" alt="img" style={{ height: '15px', width: '15px' }} />}
                  {label.warningLabel}
                </span>
              </div>
            </StepLabel>
          </Step>
        ))}
      </Stepper>
      <Button onClick={() => appendLabel()}>Hello</Button>
    </React.Fragment>
  );
};

Checklist.defaultProps = {
  activeStep: -1
};

Checklist.propTypes = {
  classes: PropTypes.object.isRequired,
  form: PropTypes.bool.isRequired,
  activeStep: PropTypes.number
};

export default withStyles(styles, { withTheme: true })(Checklist);
2
  • 2
    show your component. you have to keep this array in component state and mutate it bu setState Commented Nov 3, 2021 at 16:04
  • Hey, thanks for your comment. I updated the post to show my component code. @Robert Commented Nov 3, 2021 at 16:13

1 Answer 1

1

You need to set the labelsArray in the state and update it accordingly in order to re-render the component when the user clicks the button

Edited: A way of doing that with a state would be:

const LABELS =[
  { label: 'Hey There', sublabel1: 'How are you?' },
  { label: 'Greetings', sublabel1: 'Fellows' },
  { label: 'Awesome', sublabel1: 'Youre doing great', sublabel2: 'cool' }
];

const [labelsArray, setLabelsArray] = useState(LABELS);

const appendLabel = () => {
  let editedLabels = [...labelsArray];
  editedLabels[1].warningLabel = "Hello";
  editedLabels[1].errorLabel = "Hello";
  setLabelsArray(editedLabels);
};
Sign up to request clarification or add additional context in comments.

6 Comments

Your response makes sense but im having trouble implement such an array of objects where it would have the same effect of the .push method. Because it will show either a warningLabel if not errorLabel and vice versa. Could you please give me an guidance on that? @Diego
I edited the answer
Thanks for your attempt to help but it still does the same thing as when I wasnt using state. Which was updating the array in console but not updating the user interface. @Diego Ferrari
I edited again changing the line where I assign editedLabels inside appendLabel
Thanks! That worked!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.