React-redux container gets the new props but children do not update


#1

My redux store is being update successfully. The container has the new props however the children still have the old one.

This kind of things as I googled mostly happen from mutations. But as much I can see I don’t have any mutations.

So here is my container component Chat.jsx

import '../../../assets/stylesheets/styles.scss'

import React, { Component } from 'react'
import { connect } from 'react-redux'

import setContactId from '../redux/actions/setContactId'
import setChat from '../redux/actions/setChat'
import submitEmail from '../redux/actions/submitEmail'
import submitMessage from '../redux/actions/submitMessage'

import ddp from '../../ddp'

import Cookies from 'js-cookie'

import View from './views/View'
import Icon from './Icon'

class Chat extends Component {
  componentDidMount () {
    this.setContactIdFromCookies()
  }

  setContactIdFromCookies = () => {
    const contactId = Cookies.get('b2cContactId')
    if (contactId) this.props.setContactId(contactId)
  }

  componentWillReceiveProps = (nextProps) => {
    if (!nextProps.contactId) return
    this.getChat(nextProps.contactId)
  }

  getChat = async (contactId) => {
    console.log('getChat', contactId)
    await ddp.subscribe('Chats', {contactId})
    const chatCollection = ddp.getCollection('Chats')
    console.log('chatCollection', chatCollection)
    this.props.setChat(this.extractChatFromCollection(chatCollection))
    ddp.watch('Chats', (changedDoc, message) => {
      console.log('Chats collection item changed', changedDoc, message)
      const chatCollection = ddp.getCollection('Chats')
      this.props.setChat(this.extractChatFromCollection(chatCollection))
    })
  }

  extractChatFromCollection = collection => {
    const chatId = Object.keys(collection)[0]
    const chat = collection[chatId]
    chat._id = chatId
    return chat
  }

  emailInputRef = null

  onEmailSubmit = e => {
    e.preventDefault()
    console.log('email', this.emailInputRef.value,)

    this.props.submitEmail({
       email: this.emailInputRef.value,
       convertedPage: window.location.href,
       projectId: this.props.projectId,
       visitSessionId: this.props.visitSessionId
     })
  }

  render () {
    if (!this.props.chat._id) return null
    return (
      <div>
        <View
          visitSessionId={this.props.visitSessionId}
          defaultAdminUserName='default defaultAdminUserName'
          contactName='default contactName'
          supportName='default supportName'
          messages={this.props.chat.messages}
          onSend={this.props.submitMessage}
         />
        <Icon />
      </div>
    )
  }
}

// DONE: REDUX
// DONE: Meteor client???
// TODO: Components

Chat = connect(state => ({
  contactId: state.contactId,
  chat: state.chat
}), { setContactId, setChat, submitEmail, submitMessage })(Chat)

export default Chat

Here is the View.jsx

import React from 'react'
import PropTypes from 'prop-types'

import Messages from './Messages'
import Input from './Input'

const View = props => <div id='chat-container'>
  <div className='chat-box' style={{
    maxWidth: '350px',
    height: '469px',
    background: 'gainsboro',
    WebkitBoxShadow: '0px 0px 20px 0px rgba(0,0,0,0.75)',
    MozBoxShadow: '0px 0px 20px 0px rgba(0,0,0,0.75)',
    boxShadow: '0px 0px 20px 0px rgba(0,0,0,0.75)'
  }}>
    <div className='chat-header' style={{
      color: '#fff',
      backgroundColor: '#5ebe76',
      fontSize: '22px',
      fontWeight: 'bold',
      padding: '10px 15px'
    }}>
      <p>{props.supportName}</p>
    </div>
    <Messages
      defaultAdminUserName={props.defaultAdminUserName}
      contactName={props.contactName}
      messages={props.messages}
    />
    <Input
      visitSessionId={props.visitSessionId}
      onSend={props.onSend} />
  </div>
</div>

View.propTypes = {
  visitSessionId: PropTypes.string.isRequired,
  defaultAdminUserName: PropTypes.string.isRequired,
  contactName: PropTypes.string.isRequired,
  supportName: PropTypes.string.isRequired,
  messages: PropTypes.array.isRequired,
  onSend: PropTypes.func.isRequired
}

export default View

Here are some of the actions

setChat.js

import { SET_CHAT } from '.'

export default function (chat) {
  return {
    type: SET_CHAT,
    payload: chat
  }
}

setContactId.js

import { SET_CONTACT_ID } from '.'

export default function (contactId) {
  return {
    type: SET_CONTACT_ID,
    payload: contactId
  }
}

And here is the submitMessage.js, this is the only place I do dirty stuff.

import ddp from '../../../ddp'

export default function ({ message, visitSessionId }) {
  return (dispatch, getState) => {
    ddp.call('chat.submitContactMessage', { message, visitSessionId, contactId: getState().contactId }).then((res) => {
      console.log('res', res)
    })
  }
}

This sends an update to my db. The db gets update. The subscription function in the container works fine. Getting the new document and setting it into the store with the SET_CHAT action. And in the devtools I can see the new chat in the store and as Chat.jsx props. However the View.jsx doesn’t get the new props.