Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React tutorial StrictMode doubles all messages / removeListener seems to be broken #101

Open
nick-parker opened this issue Oct 1, 2022 · 0 comments

Comments

@nick-parker
Copy link

The current React tutorial using create-react-app puts in index.js which causes all class initiators to be executed twice. The tutorial doesn't cleanup subscriptions / listeners in its UseEffect calls so you end up with duplicate listeners and every message is shown twice in the demo app. The code below exhibits the problem with StrictMode on, but doesn't with it off.

import React, { useState, useEffect } from 'react';
import PubNub from 'pubnub';
import { PubNubProvider, usePubNub } from 'pubnub-react';

const pubnub = new PubNub({
  publishKey: 'pub-c-816a2df2-0f37-44ac-a43e-132a1f7f3672',
  subscribeKey: 'sub-c-4cf98958-0607-4897-a543-07f0daa97aa1',
  userId: 'f8681796-a1d7-4b3e-823b-67944a5c035d',
  // logVerbosity: true,
});

function App() {
  return (
    <PubNubProvider client={pubnub}>
      <Chat />
    </PubNubProvider>
  );
}

function Chat() {
  const pubnub = usePubNub();
  const [channels] = useState(['awesome-channel']);
  const [messages, addMessage] = useState([]);
  const [message, setMessage] = useState('');

  const handleMessage = event => {
    const message = event.message;
    if (typeof message === 'string' || message.hasOwnProperty('text')) {
      const text = message.text || message;
      addMessage(messages => [...messages, text]);
    }
  };

  const sendMessage = message => {
    if (message) {
      pubnub
        .publish({ channel: channels[0], message })
        .then(() => setMessage(''));
    }
  };

  useEffect( () => {
    console.log("updating pubnub")
    console.log(handleMessage)
    pubnub.addListener({ message: handleMessage });
    return () => {
      console.log("cleanup listener")
      pubnub.removeListener(handleMessage)
    }
  }, [pubnub])

  useEffect(() => {
    console.log("Updating channels or pubnub")
    console.log(channels)
    pubnub.unsubscribeAll()
    pubnub.subscribe({ channels });
    return () => {
      console.log("cleanup channels")
      pubnub.unsubscribeAll()
    }
  }, [pubnub, channels]);

  return (
    <div style={pageStyles}>
      <div style={chatStyles}>
        <div style={headerStyles}>React Chat Example</div>
        <div style={listStyles}>
          {messages.map((message, index) => {
            return (
              <div key={`message-${index}`} style={messageStyles}>
                {message}
              </div>
            );
          })}
        </div>
        <div style={footerStyles}>
          <input
            type="text"
            style={inputStyles}
            placeholder="Type your message"
            value={message}
            onKeyPress={e => {
              if (e.key !== 'Enter') return;
              sendMessage(message);
            }}
            onChange={e => setMessage(e.target.value)}
          />
          <button
            style={buttonStyles}
            onClick={e => {
              e.preventDefault();
              sendMessage(message);
            }}
          >
            Send Message
          </button>
        </div>
      </div>
    </div>
  );
}

const pageStyles = {
  alignItems: 'center',
  background: '#282c34',
  display: 'flex',
  justifyContent: 'center',
  minHeight: '100vh',
};

const chatStyles = {
  display: 'flex',
  flexDirection: 'column',
  height: '50vh',
  width: '50%',
};

const headerStyles = {
  background: '#323742',
  color: 'white',
  fontSize: '1.4rem',
  padding: '10px 15px',
};

const listStyles = {
  alignItems: 'flex-start',
  backgroundColor: 'white',
  display: 'flex',
  flexDirection: 'column',
  flexGrow: 1,
  overflow: 'auto',
  padding: '10px',
};

const messageStyles = {
  backgroundColor: '#eee',
  borderRadius: '5px',
  color: '#333',
  fontSize: '1.1rem',
  margin: '5px',
  padding: '8px 15px',
};

const footerStyles = {
  display: 'flex',
};

const inputStyles = {
  flexGrow: 1,
  fontSize: '1.1rem',
  padding: '10px 15px',
};

const buttonStyles = {
  fontSize: '1.1rem',
  padding: '10px 15px',
};

export default App;

Notice I've tried to cleanup the example to fix this, first by ensuring channels aren't double-subscribed and then by splitting the listener part of useEffect into its own call with a cleanup function, but I haven't succeeded. Are there any more detailed docs on removeListener? It doesn't seem to have any effect for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant