0
votes

I am doing some tutorials in React.js and I am fairly new to this. I have this code in the dashboard.js

import React from 'react';
import NewChatComponent from '../newChat/newChat';
import ChatListComponent from '../chatList/chatList';
import ChatViewComponent from '../chatView/chatView';
import ChatTextBoxComponent from '../chatTextBox/chatTextBox';
import styles from './styles';
import { Button, withStyles } from '@material-ui/core';
const firebase = require("firebase");

class DashboardComponent extends React.Component {

  constructor() {
    super();
    this.state = {
      selectedChat: null,
      newChatFormVisible: false,
      email: null,
      friends: [],
      chats: []
    };
  }

  render() {

    const { classes } = this.props;

    if(this.state.email) {
      return(
        <div className='dashboard-container' id='dashboard-container'>
          <ChatListComponent history={this.props.history} 
            userEmail={this.state.email} 
            selectChatFn={this.selectChat} 
            chats={this.state.chats} 
            selectedChatIndex={this.state.selectedChat}
            newChatBtnFn={this.newChatBtnClicked}>
          </ChatListComponent>
          {
            this.state.newChatFormVisible ? null : <ChatViewComponent 
              user={this.state.email} 
              chat={this.state.chats[this.state.selectedChat]}>
            </ChatViewComponent>
          }
          { 
            this.state.selectedChat !== null && !this.state.newChatFormVisible ? <ChatTextBoxComponent userClickedInputFn={this.messageRead} submitMessageFn={this.submitMessage}></ChatTextBoxComponent> : null 
          }
          {
            this.state.newChatFormVisible ? <NewChatComponent goToChatFn={this.goToChat} newChatSubmitFn={this.newChatSubmit}></NewChatComponent> : null
          }
          <Button onClick={this.signOut} className={classes.signOutBtn}>Sign Out</Button>
        </div>
      );
    } else {
      return(<div>LOADING....</div>);
    }
  }

  signOut = () => firebase.auth().signOut();

  submitMessage = (msg) => {
    const docKey = this.buildDocKey(this.state.chats[this.state.selectedChat]
      .users
      .filter(_usr => _usr !== this.state.email)[0])
    firebase
      .firestore()
      .collection('chats')
      .doc(docKey)
      .update({
        messages: firebase.firestore.FieldValue.arrayUnion({
          sender: this.state.email,
          message: msg,
          timestamp: Date.now()
        }),
        receiverHasRead: false
      });
  }

  // Always in alphabetical order:
  // 'user1:user2'
  buildDocKey = (friend) => [this.state.email, friend].sort().join(':');

  newChatBtnClicked = () => this.setState({ newChatFormVisible: true, selectedChat: null });

  newChatSubmit = async (chatObj) => {
    const docKey = this.buildDocKey(chatObj.sendTo);
    await 
      firebase
        .firestore()
        .collection('chats')
        .doc(docKey)
        .set({
          messages: [{
            message: chatObj.message,
            sender: this.state.email
          }],
          users: [this.state.email, chatObj.sendTo],
          receiverHasRead: false
        })
    this.setState({ newChatFormVisible: false });
    this.selectChat(this.state.chats.length - 1);
  }

  selectChat = async (chatIndex) => {
    await this.setState({ selectedChat: chatIndex, newChatFormVisible: false });
    this.messageRead();
  }

  goToChat = async (docKey, msg) => {
    const usersInChat = docKey.split(':');
    const chat = this.state.chats.find(_chat => usersInChat.every(_user => _chat.users.includes(_user)));
    this.setState({ newChatFormVisible: false });
    await this.selectChat(this.state.chats.indexOf(chat));
    this.submitMessage(msg);
  }

  // Chat index could be different than the one we are currently on in the case
  // that we are calling this function from within a loop such as the chatList.
  // So we will set a default value and can overwrite it when necessary.
  messageRead = () => {
    const chatIndex = this.state.selectedChat;
    const docKey = this.buildDocKey(this.state.chats[chatIndex].users.filter(_usr => _usr !== this.state.email)[0]);
    if(this.clickedMessageWhereNotSender(chatIndex)) {
      firebase
        .firestore()
        .collection('chats')
        .doc(docKey)
        .update({ receiverHasRead: true });
    } else {
      console.log('Clicked message where the user was the sender');
    }
  }

  clickedMessageWhereNotSender = (chatIndex) => this.state.chats[chatIndex].messages[this.state.chats[chatIndex].messages.length - 1].sender !== this.state.email;

  componentWillMount = () => {
      firebase.auth().onAuthStateChanged(async _usr => {
        if(!_usr)
          this.props.history.push('/login');
        else {
          await firebase
            .firestore()
            .collection('chats')
            .where('users', 'array-contains', _usr.email)
            .onSnapshot(async res => {
              const chats = res.docs.map(_doc => _doc.data());
              await this.setState({
                email: _usr.email,
                chats: chats,
                friends: []
              });
            })
        }
    });
  }
}

export default withStyles(styles)(DashboardComponent);

The problematic line of code is this one:-

newChatBtnClicked = () => this.setState({ newChatFormVisible: true, selectedChat: null });

If I set newChatFormbVisible: false, I do not get the error, however setting it to true, fails with this error:-

index.js:1375 Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check your code at dashboard.js:47. in DashboardComponent (created by WithStyles(DashboardComponent)) in WithStyles(DashboardComponent) (created by Context.Consumer) in Route (at src/index.js:28) in div (at src/index.js:25) in Router (created by BrowserRouter) in BrowserRouter (at src/index.js:24) console. @ index.js:1375 warningWithoutStack @ react.development.js:188 warning @ react.development.js:623 createElementWithValidation @ react.development.js:1785 render @ dashboard.js:44 finishClassComponent @ react-dom.development.js:15319 updateClassComponent @ react-dom.development.js:15274 beginWork @ react-dom.development.js:16262 performUnitOfWork @ react-dom.development.js:20279 workLoop @ react-dom.development.js:20320 renderRoot @ react-dom.development.js:20400 performWorkOnRoot @ react-dom.development.js:21357 performWork @ react-dom.development.js:21267 performSyncWork @ react-dom.development.js:21241 interactiveUpdates$1 @ react-dom.development.js:21526 interactiveUpdates @ react-dom.development.js:2268 dispatchInteractiveEvent @ react-dom.development.js:5085 react-dom.development.js:57 Uncaught Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

1
Hello how did you export ChatViewComponent, ChatTextBoxComponent and NewChatComponent. You should export them using default. Can you share those components code too?octobus
They are all exported the same as this one, ie:- export default withStyles(styles)(nameofcomponent);JMon
OK, I am not sure but can you try, using those components with self closing tag like <ChatViewComponent />.octobus
Self closing seems to have done the trick actually! Thanks octobus I will mark this as resolved. I think you have to create an answer so that I can mark as resolved right?JMon

1 Answers

0
votes

I am just writing this answer after we discussed with @Johann in comments section. So its easier to see by other people if they run into same type of error

OK, I am not sure but can you try, using those components with self closing tag like <ChatViewComponent />