Search code examples
javascriptreactjsreact-nativereact-hooksreact-native-firebase

State updates only after changes are made to the code


I have a react native app which I get the user from the firebase firestore database. This works properly. But when I try to get the followers length from the user object it doesn't show or change it only changes when I make a change in the code and the app refreshes.

I read somewhere that useEffect runs on the second frame so I tried putting the code outside the useEffect but nothing changes


const [followingLength, setFollowingLength] = useState(0);
const [followersLength, setFollowersLength] = useState(0);

useEffect(() => {
  const userSub = onSnapshot(doc(firestore, "Users", userId), (doc) => {
            setUser(doc.data())

            if (user.following.length !== 0) {
                setFollowingLength(user.following.length)
            }

            if (user.followers.length !== 0) {
                setFollowersLength(user.followers.length)
            }
        });
});

<Text style={{ color: colors.white }}>{followingLength}</Text>
<Text style={{ color: colors.white }}>{followersLength}</Text>

Solution

  • From the things I see definitelly:

    Issue 1: Why your useEffect does not have any dependency array? In that case the code will be executed in every render which will be buggy and expensive.

    Issue 2: Do you know that setUser does not update user object immediatelly and user in your if is "old" and closure captured?

    Issue 3: Do you know that onSnapshot returns unsubscribe function that needs to be called to stop the listener. In your case you are adding 1 additional listener every render which is also buggy and expensive.

    Im not 100% sure those combination of issues is exact the source of your problems, but they definitelly should be solved

    Note: You can use useMemo to calculate following and followers.

    const [user, setUser] = useState();
    const followingLength = useMemo(() => {
      return user?.following?.length || 0;
    }, [user]);
    
    const followersLength = useMemo(() => {
      return user?.followers?.length || 0;
    }, [user]);
    
    useEffect(() => {
      const unsubscribe = onSnapshot(doc(firestore, "Users", userId), (doc) => {
        setUser(doc.data());
    
        // Or
        // const u = doc.data();
        // setUser(u);
        // setWhateverElse from "u", not "user"
    
      });
    
      return unsubscribe;
    }, [userId]);