Are you using this inside useffect?
# help
m
Are you using this inside useffect?
You need to clear the subscription on unmount
In order to have only one subscription active
g
Great to catch this... I had a subscribe in onAuthStateChange event inside useEffect. But every once in while was noticing multiple subscribe events... must be I logged out and logged back in...
m
You first need to store the subscription like this: ‘’’ this.commentsSubscription = this.$supabase .from("comments") .on("INSERT", payload => { if(String(payload.new.book_id) === String(this.bookId)) { this.comments = [...comments, payload.new] } }) .subscribe(); ‘’’ And on destroy do this: ‘’’ this.$supabase.removeSubscription(this.commentsSubscription); }, ‘’’
g
Interesting... I must have logged out and logged in quickly in my testing... I found this comment... "Removing subscriptions is a great way to maintain the performance of your project's database. Supabase will automatically handle cleanup 30 seconds after a user is disconnected, but unused subscriptions may cause degradation as more users are simultaneously subscribed." .... this is different that the original question, sorry for the hijack but saved me from a future problem
n
Thanks! I have another question if youre familiar with React
Copy code
js
  useEffect(() => {
    const mySubscription = supabase
      .from("posts")
      .on("INSERT", (payload) => {
        console.log(posts);
      })
      .subscribe();
    return () => {
      supabase.removeSubscription(mySubscription);
    };
  }, []);
This is my useEffect now 👆 , but see where it says to console.log posts? When the component first mounts (in a different useEffect), it changes the state posts to an array. But when this subscription runs, it for some reason logs out the default value of posts instead of the current value.
m
Can you show the whole component?
n
Sure
Copy code
js
const Messages = () => {
  const [posts, setPosts] = useState([]);
  const router = useRouter();
  const { id } = router.query;

  useEffect(() => {
    fetchPosts();
  }, [id]);

  useEffect(() => {
    console.log(posts);
  }, [posts]);

  const fetchPosts = async () => {
    let { data, error } = await supabase.from("posts").select("*").eq("room", id);
    error ? console.log(error) : setPosts(data);
  };

  useEffect(() => {
    const mySubscription = supabase
      .from("posts")
      .on("INSERT", (payload) => {
        console.log(posts);
      })
      .subscribe();
    return () => {
      supabase.removeSubscription(mySubscription);
    };
  }, []);

  return (
    <div>
      {posts.map((post) => {
        return <p key={post.id}>{post.content}</p>;
      })}
    </div>
  );
};
its very simple but I must be doing something wrong lol @User
the default value of posts is just an empty array
const [posts, setPosts] = useState([]);
Line 15 logs the posts when ever it changes, line 27 is when the subscription runs and for some reason has the default value instead of the current value
m
@Null the problem is that you need to run the useEffect with the dependency of posts
If you want to use posts inside it
If you had eslint from create react app, it will warn you
Copy code
js
  useEffect(() => {
    const mySubscription = supabase
      .from("posts")
      .on("INSERT", (payload) => {
        console.log(posts);
      })
      .subscribe();
    return () => {
      supabase.removeSubscription(mySubscription);
    };
  }, [posts]);
You need to have it Like this @Null
n
I was thinking that but the issue is I'm not trying to console.log , I want to add the payload to the array posts
setPosts([...posts, payload.new]).
I was using the console log to debug and thats how I found out why I wasn't getting back the array spread, it comes up blank from its default value. And adding posts into the dependencies wouldn't work due to it not changing.
I'm pretty stumped
or it would cause an infinite loop
m
@Null instead of doing the add there, call a function handleAdd(payload)
And in that function
Do the setState
Copy code
js
  useEffect(() => {
    const mySubscription = supabase
      .from("posts")
      .on("INSERT", (payload) => {
        this.handleInsert(payload)
      })
      .subscribe();
    return () => {
      supabase.removeSubscription(mySubscription);
    };
  }, [posts]);

Const handleInsert = (payload) => {
    setPosts(prevPosts => […prevPosts, payload.new])

}
n
Bit of a noob question but what the
this
doing?
from
this
.handleInsert(payload)
m
HandleInsert then
Sorry
Im writing vue atm
😬
You dont need the this keyword
n
oh haha no worries
m
Does it work?
n
im getting the same result
this is very odd 😅
Copy code
js
  useEffect(() => {
    const mySubscription = supabase
      .from("posts")
      .on("INSERT", (payload) => {
        handleInsert(payload);
      })
      .subscribe();
    return () => {
      supabase.removeSubscription(mySubscription);
    };
  }, [posts]);

  const handleInsert = (newPost) => {
    setPosts([...posts, newPost.new]);
    console.log(posts);
  };
Okay I am getting a different result, I believe the useEffect isn't running as nothing happens.
@User
m
On the useEffect
You dont need posts anymore
n
I got it working I believe
yep
i removed it and it worked
m
Do an empty array as dependency
n
One question, how does this function work exactly?
Copy code
js
    setPosts((prevPosts) => [...prevPosts, newPost.new]);
What is the prevPosts variable?
that version of setPosts 👆 worked
but this doesnt
setPosts([...posts, newPost.new]);
m
PrevPosts is the posts at the previous iteration
n
so this is where I maybe when wrong haha
Oh is this a thing you can do with useState?
I appreciate your help so much!
m
Ye
Most of the time
SetState(counter + 1) and setState(prevCounter => prevCounter +1)
Is the same
But the second one will always work
The first one, if the state is changed somewhere at the same time, it will not have the value yet ( it will not be synced)
n
Thank you again for all your help, ive been really stumped on this for days now 😅
m
Np. Good Luck with the app