Issues arise when implementing ReactJS transitions for progress bars

As a newcomer to the world of ReactJS, I have been exploring the FB documentations and online tutorials to kickstart my test project.

Within this project, I wanted to implement a progress bar that visually represents the user's progression through filling out forms across three pages. Everything was going smoothly until I decided to add some transition effects to enhance the progress bar.

I wrote the code below with the intention of passing a prop from the parent component to the child progressBar component to determine the percentage completion of the progress bar.

In the constructor, I initialized the default width to 0 and updated it in componentDidMount based on the percentage received from the parent. While I successfully managed to set the style, unfortunately, the transition effect did not seem to work as expected. My aim was to create a sleek progress bar that smoothly transitions from 0% width to the specified percentage provided via props.

Here is how my code looks:

ProgressBar component

import './style.scss';
import React from 'react';
import classnames from 'classnames';

class ProgressBar extends React.Component {

    constructor(props) {
        super(props);
        this.state = { progressionStyle : { } }
    }

    componentDidMount() {
        this.setState({
            progressionStyle : {
                width: this.props.progression,
                transition: 'all 1500ms ease'
            },
            scene1: (this.props.scene1 === 'active') ? 'active' : (this.props.scene1 === 'done')   ? 'done' : '',
            scene2: (this.props.scene2 === 'active') ? 'active' : (this.props.scene2 === 'done')     ? 'done' : '',
            scene3: (this.props.scene3 === 'active') ? 'active' : (this.props.scene3 === 'done')   ? 'done' : ''
        });
    }

    render() {
        return (
            <div className="progress-bar">
                <div className="progress-bar__inner">

                    <div className="progress-bar__progress">
                        <div className={classnames('progress-bar__progress-fill', this.props.active)} style={this.state.progressionStyle}></div>
                    </div>

                    <div id="scene1" className="progress-bar__element">
                        <i className={classnames('progress-bar__icon', this.state.scene1)}></i>
                        <span className="progress-bar__label">Scene 1</span>
                    </div>

                    <div id="scene2"  className="progress-bar__element">
                        <i className={classnames('progress-bar__icon', this.state.scene2)}></i>
                        <span className="progress-bar__label">Scene 2</span>
                    </div>

                    <div id="scene3" className="progress-bar__element">
                        <i className={classnames('progress-bar__icon', this.state.scene3)}></i>
                        <span className="progress-bar__label">Scene 3</span>
                    </div>

                </div>
            </div>
        );
    }
}

export default ProgressBar;

Answer №1

It is not recommended to directly set the nested state; you should approach it like this:

componentDidMount() {
  var newStyle = {...this.state.style}

  newStyle.width = this.props.progression
  newStyle.transition = 'all 500ms ease-in'

  this.setState({style: newStyle});
}

Additionally, remember to update your state in the componentWillReceiveProps function when updating based on props.

componentWillReceiveProps(nextProps) {
  var updatedStyle = {...this.state.style}

  updatedStyle.width = nextProps.progression
  updatedStyle.transition = 'all 500ms ease-in' 

  this.setState({style: updatedStyle});
}

Answer №2

In order to achieve this particular effect, I discovered that the solution involved wrapping the style in a function and then calling it with request animation frame as shown below:

 componentDidMount() {
        requestAnimationFrame(()=> {
            this.showProgress();
        });
    }

    showProgress() {
        var style = { };
        style.width = this.props.progression;
        style.transition = 'all 1500ms ease-in';
        this.setState({style});
    }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Enhancing User Experience on Android Devices: Automatic Website Zoom-In Feature for Responsive Design

For the first time, I am delving into creating a responsive website design. I seem to be encountering difficulties when it comes to smartphones. I have been using the following meta-tag to ensure that the website loads "zoomed in". (I found this method on ...

Issue with alignment on the printed version of an HTML document

While attempting to print an auto-generated HTML page through my Thermal POS printer, I encountered a large left margin issue. The application is developed using PyQt5, and I had to resort to a python script to generate the HTML code. Unfortunately, in the ...

Issue: Importing an ES Module in React-gauge-chart causing error in NextJs

an error appears indicating the following: When attempting to render the package component, an issue arises with the require() function used on ES Module /node_modules/d3/src/index.js from /node_modules/react-gauge-chart/dist/GaugeChart/index.js. The s ...

Ways to align content on navbar (Bootstrap 5)

I am currently working on a minimal navbar design using Bootstrap 5. In this setup, there are two main elements - the 'navbar-brand' for the logo/brand and the navigation links. My goal is to have the brand/logo aligned all the way to the left, ...

Tips for specifying the type when utilizing the spread operator to pass props

type TypeData = { data: { id: string; class: string; name: string; country: string; ew_get_url: string; ew_post_url: string; rocket_id: string; pages: { landing: { h1: string; h2: string; } ...

Error: TypeScript React SFC encountering issues with children props typing

I am currently working with a stateless functional component that is defined as follows: import { SFC } from "react"; type ProfileTabContentProps = { selected: boolean; }; const ProfileTabContent: SFC<ProfileTabContentProps> = ({ selected, child ...

A caution about using componentWillMount with functions that update state is important to consider

I am facing an issue with a clear button in my render method. <Button onClick={this.clearFilters(data)}> CLEAR </Button> The button is supposed to call a function that clears out a state. clearFilters(data){ if (!data || !this.state) { ...

Guide on Updating Favicon for Dark and Light Theme in Next.js Version 13 or 14

Currently, I am developing a web application using Next.js 14 and the App Router. One of the requirements is to have the favicon dynamically change based on the user's color scheme preference, switching between black and white versions when transition ...

Adjust top position dynamically during resizing

When resizing the window, I am facing an issue with the image going outside of the box. I believe adjusting the position top of the image based on the box height might help in fitting the image properly within the box. $(window).resize(function() { va ...

Stop text from overflowing when it reaches the maximum width in flexbox

A basic flexbox layout is displayed with an image next to text, aiming for this layout: #container { align-items: center; background: black; display: flex; justify-content: center; padding: 10px; width: 500px; /* Dynamic */ } #image { bac ...

Tips for positioning two divs side by side in block formation

I'm attempting to display two distinct div elements as blocks, one for the name and the other for the names. Here is the Fiddle The names block should be displayed as a separate block next to the name div, regardless of screen responsiveness. How ca ...

Animating with React using the animationDelay style does not produce the desired effect

Is there a way to apply an animation to each letter in a word individually when hovering over the word? I want the animation to affect each letter with an increasing delay, rather than all at once. For example, if scaling each letter by 1.1 is the animatio ...

When a custom icon is clicked in the vue-select dropdown, the custom method is not activated

In my current project, I am creating a vue-component based on vue-select. Within this component, I have added a custom info Icon. The issue I am facing is that when the user clicks on the Icon, instead of triggering my custom method getInfo, it opens the s ...

Troubleshooting Images in a React Application Integrated with WordPress API

I am struggling to understand why this GET request is consistently returning a 404 error. I have thoroughly tested the URL using Postman and everything seems to be in working order for the title and excerpt, but the images are causing some issues. Does a ...

Creating a function to limit the display value of Material UI Autocomplete similar to Material UI Multiple Select's renderValue

Incorporating Material UI Features Utilizing the Material UI Multiple Select, you have the ability to truncate the displayed value after selection instead of wrapping onto another line by setting the renderValue to .join for the selected options, enabling ...

Add a new string to a class within a Vue.js component

Hey there, currently working on a Vue component where I am iterating through a list of countries. Here's how it looks: <div v-for="i in countries" :key="i.id"> {{i.name}} <span class="flag-icon-gr"></span> I want to dynamically ...

Tips for incorporating HTML into a material-ui Snackbar message

Recently, I've been experimenting with integrating (react) material-ui into my application. It's quite similar to the example provided in the documentation: function MySnackbarContentWrapper(props) { const classes = useStyles1(); const { ...

Find out the keycode of an event in ReactJS when a key is released

Whenever I try to get keyCode on a keyUp event, it always returns 0. Why is this happening? I want to avoid using keypress and similar methods, and I also need to utilize an arrow function: handleKeyPress = (e, type) => { let KeyCode = e.charCode; ...

Is there excessive spacing following an A tag or an img tag?

Hi there, I'm currently facing an issue while building a table cell using the div tag. Specifically, I have encountered some unwanted spacing after my img within the cell. <div style="display:table"> <div style="display:row"> <div s ...

Setting up the initialization process of a React application for production environment

As someone new to create-react-app and npm, I'm facing issues with deploying my app to production. What I want is to start a specific js file when my app starts, in addition to running the usual <code>react-scripts start. That's why in my p ...