0

I'm learning react. In the below Alert component I'm updating a simple alert message and setting the opacity to 1 and then fading it out with a CSS transition. This is in a simple to do app to get ramped up on react.

The issue I'm having is when I update the alert text this.props.message the previous message text shows for a fraction of a second after opacity is set to 1, before the new message replaces it. It is very quick but it seems like there is a race condition as the DOM or React renders the text change slower than the style change. Let me know if there is a way I can omit the hiccup and set opacity after the text message has changed. Thanks.

var TodoApp = React.createClass({
    getInitialState: function() {
        return { 
            items: [],
            alert: { message: '', success: null }
        };
    }
    genericMethod: function() {
         ...
         this.setState({ alert: { message: message, success: true } });
         ...
    },
    ...
    render: function() {
        return (
            <div>
                <Alert message={this.state.alert.message} success={this.state.alert.success} />
                <ItemInput onItemSubmit={this.addItem} />
                <ItemList items={this.state.items} deleteItem={this.deleteItem} toggleComplete={this.toggleComplete} />
            </div>
        );
    }
});

...

var Alert = React.createClass({
    delayTime: 1000,
    getInitialState: function() {
        return {
            visible: false
        };
    },
    componentWillReceiveProps: function() {
        this.setState({ visible: true }, function() {
            this.setTimer();
        });
    },
    setTimer: function() {
        setTimeout(function(argument) {
            this.setState({ visible: false });
        }.bind(this), this.delayTime);
    },
    render: function() {
        var style = {
            opacity: (this.state.visible ? 1 : 0),
            transition: 'opacity '+(this.state.visible ? 0 : this.delayTime)+'ms'
        };
        var alertClass = 'alert'+(this.props.success ? ' success' : ' error');
        return (
            <div className={alertClass} style={style}>
                {this.props.message}
            </div>
        );
    }
});
Gadget Blaster
  • 759
  • 5
  • 15
  • Here is a JSFiddle: https://jsfiddle.net/ojdemzLt/ If you cant duplicate your problem I can try to help you. – barracuda Dec 05 '15 at 03:36
  • I updated the fiddle but can't reproduce the issue without duplicating the whole todo app, which requires a simple php backend. I did narrow it down however. In my top level `getInitialState` I'm setting an object with both the todo items and the alert: `{ items: [ ], alert: { message: '', success: null } }`. By setting a breakpoint on the alert I was able to see that changing anything in the items array was causing a render cycle on Alert before the new message was set. I'm going to re-work the alert scope or the ajax callback which sets the alert. This was helpful. Thanks. – Gadget Blaster Dec 07 '15 at 17:19

1 Answers1

0

The solution was to remove the alert state from the top level Todo class. So { items: [ ], alert: { message: '', success: null } } became just { items: [ ] } and then call a method on the child Alert component from my Todo component with <Alert ref="alert" /> and this.refs['alert'].triggerAlert(message, true); (as seen in this SO answer React.js - access to component methods) instead of watching componentWillReceiveProps in the Alert component. This made it so I was not prematurely rendering the Alert component before the new message was set every time the Todo items were added or updated.

Community
  • 1
  • 1
Gadget Blaster
  • 759
  • 5
  • 15