Redux Saga 不等待 Firebase 服务 return
Redux Saga not waiting for Firebase service to return
SignUpSaga 已损坏。它不会等待“yield put(updateUserAction(user));”到 return 一个值,它只是 returns undefined 破坏应用程序然后,在 returns 之后注册服务.
如何让它等待?我以为这就是屈服的作用。
部分 redux 包:
export const updateUserAction = (user: User | null): UpdateUserActionType => ({
type: UPDATE_USER,
user,
});
...
export const userReducer = (
state: StateSlice = initialState.user,
action: UpdateUserActionType
): StateSlice => {
switch (action.type) {
case UPDATE_USER:
return updateHandler(state, action);
case SIGN_OUT:
return signOutHandler();
default:
return state;
}
};
互动者
export class SignUpInteractor {
signUpService: SignUpService;
constructor(signUpService: SignUpService) {
this.signUpService = signUpService;
}
async signUp(
firstName: string,
lastName: string,
credential: Credential
): Promise<User> {
const user = new User(firstName, lastName, credential.email);
return this.signUpService.signUpUser(user, credential);
}
}
传奇
function* signUpSaga(action: SignUpActionType) {
const { firstName, lastName, credential } = action;
const service = new FirebaseLogin();
const interactor = new SignUpInteractor(service);
const user = yield call(() => {
interactor.signUp(firstName, lastName, credential);
});
yield put(updateUserAction(user));
}
最后,注册服务:
export class FirebaseLogin implements SignUpService {
async signUpUser(user: User, credential: Credential): Promise<User> {
var user: User;
try {
db.app
.auth()
.createUserWithEmailAndPassword(credential.email, credential.password)
.then((authData) => {
db.app
.database()
.ref("users/" + authData.user.uid)
.set({
uid: authData.user.uid,
email: credential.email,
firstName: user.firstName,
lastName: user.lastName,
})
.then(() => {
db.app
.database()
.ref("users/" + authData.user.uid)
.once("value")
//do this to make sure data was returned as values, not resolved later by firebase.
.then((snapchat) => {})
.then(() => {
console.log("returning");
return user;
});
})
.catch((error) => {
return new User("error", "error", "err@err.com");
});
})
.catch((error) => {
console.log("error here");
return new User("error", "error", "err@err.com");
});
} catch (error) {
console.log("error here");
return new User("error", "error", "err@err.com");
}
}
我认为主要问题是您如何使用 call
:
const user = yield call(() => {
interactor.signUp(firstName, lastName, credential);
});
您正在传递一个同步函数,该函数将立即启动异步调用和 return。此外,该函数 return 什么都没有,因此 undefined
.
您真正想要的是告诉中间件进行异步调用,从而等待 promise 被解析:
const user = yield call(interactor.signUp, firstName, lastName, credential);
此外,您的代码看起来 wayyyy 比需要的更复杂:手动编写 Redux 代码,reducer 中的额外函数,为操作定义单独的 TS 类型对象,还有这个“交互者”和“服务”位。在此示例中,即使使用 sagas 也太过分了。您应该使用 our official Redux Toolkit package 并遵循我们关于将 Redux 与 TS 结合使用的建议。这将大大简化您的代码。
如果我自己写这个,我会让 signUp
部分成为一个独立的异步函数,并使用 RTK 的 createAsyncThunk
:
async function signUpUser(user: User, credential: Credential): Promise<User> {
// omit Firebase code
return user;
}
interface SignUpArgs {
firstName: string;
lastName: string;
credential: Credential;
}
const signUp = createAsyncThunk(
'users/signUp',
async ({firstName, lastName, credential}: SignUpArgs) => {
const user = new User(firstName, lastName, credential.email);
return signUpUser(user, credential);
}
)
type UserState = User | null;
const initialState : UserState = null;
const userSlice = createSlice({
name: 'users',
initialState, // whatever your state actually is,
reducers: {
// assorted reducer logic here
signOut(state, action) {
return null;
}
},
extraReducers: builder => {
builder.addCase(signUp.fulfilled, (state, action) => {
return action.payload
});
}
})
最终代码少了很多,尤其是 如果您在 reducer 中进行任何实际有意义的状态更新。
SignUpSaga 已损坏。它不会等待“yield put(updateUserAction(user));”到 return 一个值,它只是 returns undefined 破坏应用程序然后,在 returns 之后注册服务.
如何让它等待?我以为这就是屈服的作用。
部分 redux 包:
export const updateUserAction = (user: User | null): UpdateUserActionType => ({
type: UPDATE_USER,
user,
});
...
export const userReducer = (
state: StateSlice = initialState.user,
action: UpdateUserActionType
): StateSlice => {
switch (action.type) {
case UPDATE_USER:
return updateHandler(state, action);
case SIGN_OUT:
return signOutHandler();
default:
return state;
}
};
互动者
export class SignUpInteractor {
signUpService: SignUpService;
constructor(signUpService: SignUpService) {
this.signUpService = signUpService;
}
async signUp(
firstName: string,
lastName: string,
credential: Credential
): Promise<User> {
const user = new User(firstName, lastName, credential.email);
return this.signUpService.signUpUser(user, credential);
}
}
传奇
function* signUpSaga(action: SignUpActionType) {
const { firstName, lastName, credential } = action;
const service = new FirebaseLogin();
const interactor = new SignUpInteractor(service);
const user = yield call(() => {
interactor.signUp(firstName, lastName, credential);
});
yield put(updateUserAction(user));
}
最后,注册服务:
export class FirebaseLogin implements SignUpService {
async signUpUser(user: User, credential: Credential): Promise<User> {
var user: User;
try {
db.app
.auth()
.createUserWithEmailAndPassword(credential.email, credential.password)
.then((authData) => {
db.app
.database()
.ref("users/" + authData.user.uid)
.set({
uid: authData.user.uid,
email: credential.email,
firstName: user.firstName,
lastName: user.lastName,
})
.then(() => {
db.app
.database()
.ref("users/" + authData.user.uid)
.once("value")
//do this to make sure data was returned as values, not resolved later by firebase.
.then((snapchat) => {})
.then(() => {
console.log("returning");
return user;
});
})
.catch((error) => {
return new User("error", "error", "err@err.com");
});
})
.catch((error) => {
console.log("error here");
return new User("error", "error", "err@err.com");
});
} catch (error) {
console.log("error here");
return new User("error", "error", "err@err.com");
}
}
我认为主要问题是您如何使用 call
:
const user = yield call(() => {
interactor.signUp(firstName, lastName, credential);
});
您正在传递一个同步函数,该函数将立即启动异步调用和 return。此外,该函数 return 什么都没有,因此 undefined
.
您真正想要的是告诉中间件进行异步调用,从而等待 promise 被解析:
const user = yield call(interactor.signUp, firstName, lastName, credential);
此外,您的代码看起来 wayyyy 比需要的更复杂:手动编写 Redux 代码,reducer 中的额外函数,为操作定义单独的 TS 类型对象,还有这个“交互者”和“服务”位。在此示例中,即使使用 sagas 也太过分了。您应该使用 our official Redux Toolkit package 并遵循我们关于将 Redux 与 TS 结合使用的建议。这将大大简化您的代码。
如果我自己写这个,我会让 signUp
部分成为一个独立的异步函数,并使用 RTK 的 createAsyncThunk
:
async function signUpUser(user: User, credential: Credential): Promise<User> {
// omit Firebase code
return user;
}
interface SignUpArgs {
firstName: string;
lastName: string;
credential: Credential;
}
const signUp = createAsyncThunk(
'users/signUp',
async ({firstName, lastName, credential}: SignUpArgs) => {
const user = new User(firstName, lastName, credential.email);
return signUpUser(user, credential);
}
)
type UserState = User | null;
const initialState : UserState = null;
const userSlice = createSlice({
name: 'users',
initialState, // whatever your state actually is,
reducers: {
// assorted reducer logic here
signOut(state, action) {
return null;
}
},
extraReducers: builder => {
builder.addCase(signUp.fulfilled, (state, action) => {
return action.payload
});
}
})
最终代码少了很多,尤其是 如果您在 reducer 中进行任何实际有意义的状态更新。