我不知道为什么,但由于某种原因,我在调用更新时没有旧状态的值,它似乎总是具有默认状态的值。
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);
这里我总是得到输出"setting session"具有默认状态值和"设置用户"。使用默认状态值。
使用这个钩子的代码:
const {loadSession,session,users} = useTSession();
useEffect(()=>{
if(sessionId&&!session){
const unsub = loadSession(sessionId);
return () => {
unsub()
}
}
},[]);
然后在我的主组件中,我首先得到session
,user
未定义。然后是user
,session
未定义
如果我添加另一个钩子来获取更多的数据,那么它有同样的问题。所以我真的不知道这里出了什么问题。
如果我像这样拆分钩子的内部状态:
const [iSession, setISession] = useState<any>();
const [iUser, setIUser] = useState<any>();
return (
<TSessionContext.Provider
value={{
...state,
users:iUser,
session:iSession,
loadSession,
}}
>
{children}
</TSessionContext.Provider>
);
那么它似乎可以正常工作,不确定为什么其他变体不能。
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();
};
}