title: state changes without calling setState
body: <p>So I'm trying to build a <code>Notifications</code> component in React. The component's state holds an array of notifications which are objects. One of their keys is 'seen'. The purpose of seen, as you can probably guess, is mainly visual. Everytime a user clicks on a notification, I run a function that's supposed to set the notification as seen in the database (for consistency) and in the local state (for UI).</p>
  
  <p>The database part works great, but for some reason the state change doesn't work. When I put some <code>console.log</code>s, weirdly enough I see that the 'seen' property changes to 1 before I even call <code>this.setState</code>. I've been at it for hours now and I can't figure out what's happening.</p>
  
  <p>And now, some code:</p>
  
  <pre><code>import React, {Component} from 'react';
  import {connect} from 'react-redux';
  import classes from './Notifications.module.css';
  import * as actions from '../../../store/actions';
  
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
  import moment from 'moment';
  import {Redirect} from 'react-router-dom';
  
  class Notifications extends Component {
    constructor(props) {
      super(props);
  
      // Set an interval to update notifications every 4 minutes.
      this.update = setInterval(() =&gt; {
        this.props.fetchNotifications(this.props.username)
      }, 240000)
    }
  
    state = {
      opened: false,
      count: 0,
      notifications: []
    }
  
    componentDidUpdate(prevProps, prevState) {
      if (!prevProps.username &amp;&amp; this.props.username) this.props.fetchNotifications(this.props.username);
      if (!prevProps.notifications &amp;&amp; this.props.notifications) {
        this.setState({notifications: this.props.notifications, count: this.props.notifications.filter(not =&gt; !not.seen).length});
      }
  
      if (this.props.notifications) {
        if (JSON.stringify(this.state.notifications) !== JSON.stringify(prevState.notifications)) {
          this.setState({count: this.state.notifications.filter(not =&gt; !not.seen).length})
        }
      }
    }
  
    componentWillUnmount() {
      // Clear the update interval
      clearInterval(this.update);
    }
  
    redirect(model, model_id) {
      switch (model) {
        case 'sealant_customer':
          return &lt;Redirect to={`/profile/sealant-customer/${model_id}`} /&gt;;
        case 'unapproved_business':
          return &lt;Redirect to={`/profile/unapproved-business/${model_id}`} /&gt;;
        case 'business':
          return &lt;Redirect to={`/profile/business/${model_id}`} /&gt;;
        case 'missed_call':
          return &lt;Redirect to={`/data/missed-calls`} /&gt;;
        default: return null;
      }
    }
  
    render() {
      let content = (
        &lt;React.Fragment&gt;
          &lt;div className={classes.svgWrapper}&gt;
            &lt;p className={classes.counter} style={{opacity: this.state.count === 0 ? '0' : '1'}}&gt;{this.state.count}&lt;/p&gt;
            &lt;FontAwesomeIcon icon='bell' onClick={() =&gt; this.setState(prevState =&gt; ({opened: !prevState.opened}))} /&gt;
          &lt;/div&gt;
  
          {this.state.opened &amp;&amp; &lt;div className={classes.notificationsWrapper}&gt;
            &lt;ul className={classes.notificationsList}&gt;
              {this.state.notifications.length !== 0 ? Array.from(this.state.notifications).map(notifi =&gt; {
                let icon;
                switch (notifi.model) {
                  case 'sealant_customer':
                  case 'person':
                    icon = 'user';
                    break;
                  case 'business':
                  case 'unapproved_business':
                    icon = 'warehouse';
                    break;
                  default: icon = 'user';
                }
                let classArray = [classes.notification];
                if (!notifi.seen) classArray.push(classes.unseen);
  
                return (
                  &lt;li key={notifi.id} className={classArray.join(' ')} onClick={ () =&gt; {
                    // If already seen, simply redirect on click.
                    if (notifi.seen) return this.redirect(notifi.model, notifi.model_id);
  
                    let newNotifications = [...this.state.notifications];
  
                    // If not seen, mark as seen in State &amp; in Database.
                    let index = newNotifications.findIndex(not =&gt; notifi.id === not.id);
                    newNotifications[index].seen = 1;
                    this.setState({ notifications: newNotifications});
                    this.props.markSeen(notifi.id, this.props.username);
  
                    // Redirect.
                    return this.redirect(notifi.model, notifi.model_id);
                  }}&gt;
                    &lt;div className={classes.iconWrapper}&gt;
                      &lt;FontAwesomeIcon icon={icon} /&gt;
                    &lt;/div&gt;
  
                    &lt;div className={classes.textWrapper}&gt;
                      &lt;p className={classes.msg}&gt;
                        {notifi.message}
                      &lt;/p&gt;
  
                      &lt;label className={classes.ago}&gt;
                        {moment(notifi.date).fromNow()}
                      &lt;/label&gt;
                    &lt;/div&gt;
                  &lt;/li&gt;
                )
              }) : &lt;li className={classes.notification} style={{cursor: 'default'}}&gt;&lt;p style={{whiteSpace: 'nowrap'}}&gt;No notifications to show...&lt;/p&gt;&lt;/li&gt;}
            &lt;/ul&gt;
          &lt;/div&gt;}
        &lt;/React.Fragment&gt;
      )
      return (
        &lt;div className={classes.wrapper}&gt;
          {content}
        &lt;/div&gt;
      )
    }
  }
  
  const mapStateToProps = state =&gt; {
    return {
      username: state.auth.username,
      notifications: state.data.notifications
    };
  };
  
  const mapDispatchToProps = dispatch =&gt; {
    return {
      fetchNotifications: username =&gt; dispatch(actions.fetchNotifications(username)),
      markSeen: (id, username) =&gt; dispatch(actions.markSeen(id, username))
    };
  };
  
  export default connect(mapStateToProps, mapDispatchToProps)(Notifications);
  </code></pre>
  
  <p>Any help would be appreciated.</p>