【问题标题】:Problem with state in react hooks while using firebase-firestore使用 firebase-firestore 时反应钩子中的状态问题
【发布时间】:2021-11-22 03:59:21
【问题描述】:

我不知道为什么,但由于某种原因,我在调用更新时没有旧状态的值,它似乎总是具有默认状态的值。

const defaultState:RootState = {
    loadSessions:(groupId:string,lectureId:string)=>{},
    loadSession:(sessionId:string)=>()=>{},
    userJoined:(user:IUser)=>{}
};

const TSessionContext = React.createContext<RootState>(defaultState);

export const TSessionProvider: FC = ({ children }) => {
    const [state, setState] = useState<RootState>(defaultState);

    const loadSession = (sessionId:string)=>{
        console.info("Calling load session");
        const unsubSession = db.collection(COLLECTION_REF).doc(sessionId)
            .onSnapshot((snapshot) => {
                const session = snapshot.data() as ISession;
                console.info("setting session",state);
                setState({
                    ...state,
                    session
                });
            });

        const unsubUsers = db.collection(`${COLLECTION_REF}/${sessionId}/users`)
            .onSnapshot((querySnapshot) => {
                const users:IUser[] = [];
                querySnapshot.forEach((doc) => {
                    users.push(doc.data() as IUser)
                });
                console.info("setting users",state);
                setState({
                    ...state,
                    users
                });
            });

        return ()=>{
            unsubUsers();
            unsubSession();
        };
    }

    return (
        <TSessionContext.Provider
            value={{
                ...state,
                loadSession,
            }}
        >
            {children}
        </TSessionContext.Provider>
    );
};

export const useTSession = () =>  useContext(TSessionContext);

在这里我总是得到带有默认状态值的输出“设置会话”和带有默认状态值的“设置用户”。

我使用这个钩子的代码:

const {loadSession,session,users} = useTSession();
    
useEffect(()=>{
  if(sessionId&&!session){
    const unsub = loadSession(sessionId);
    return () => {
      unsub()
    }
  }
},[]);

然后在我的主要组件中,我首先得到sessionuser 未定义。 然后usersession 未定义。

如果我添加另一个获取更多数据的钩子,那么它也有同样的问题。所以我真的不确定这里有什么问题。

如果我像这样拆分我的钩子内部状态:

const [iSession, setISession] = useState<any>();
const [iUser, setIUser] = useState<any>();

return (
    <TSessionContext.Provider
        value={{
            ...state,
            users:iUser,
            session:iSession,
            loadSession,
        }}
    >
        {children}
    </TSessionContext.Provider>
);

然后它似乎可以正常工作,不知道为什么其他变体没有。

【问题讨论】:

    标签: reactjs google-cloud-firestore react-hooks


    【解决方案1】:

    setState 是异步的,所以当你这样调用它们时,你会覆盖之前的状态。我还没有看到像你正在使用的模式,但你不应该在同一个函数中尝试两次写入状态,因为你会遇到问题,你可能会更新到这个

    const loadSession = async(sessionId:string)=>{
            const newState = {}
            console.info("Calling load session");
            const unsubSession = await db.collection(COLLECTION_REF).doc(sessionId)
                .onSnapshot((snapshot) => {
                    const session = snapshot.data() as ISession;
                    console.info("setting session",state);
                    newState.session = session
                });
    
            const unsubUsers = await db.collection(`${COLLECTION_REF}/${sessionId}/users`)
                .onSnapshot((querySnapshot) => {
                    const users:IUser[] = [];
                    querySnapshot.forEach((doc) => {
                        users.push(doc.data() as IUser)
                    });
                    console.info("setting users",state);
                    newState.users = users
                });
                setState({
                  ...state,
                  ...newState,
               });
    
            return ()=>{
                unsubUsers();
                unsubSession();
            };
        }
    

    【讨论】:

    • 嗯,但 onSnapshot 也是异步的。因此,在这种情况下,可能会在会话之前获取用户集合。还是我错了?
    • 是的,你是对的,使 func 异步并添加等待,抱歉错过了
    • 另一个更简单的答案是拆分状态有 const [session, setSession] = useState(null) const [users, setUsers] = useState(null) 这样你就不用担心了
    • 是的,我做到了,它奏效了。我只是想了解为什么只有一种状态的版本不起作用。
    • 它是异步的,所以 ...state 在函数开始之前查看当前状态,因此第二个完成将覆盖第一个完成。我希望我的原始答案能正确解释
    猜你喜欢
    • 2020-10-23
    • 1970-01-01
    • 2021-07-19
    • 1970-01-01
    • 2021-03-22
    • 2022-11-01
    • 1970-01-01
    • 2020-01-31
    • 2021-10-12
    相关资源
    最近更新 更多