Home > Back-end >  Pushing into an array object in react but not rendering on the screen
Pushing into an array object in react but not rendering on the screen

Time:11-04

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);

CodePudding user response:

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);
};
  • Related