如何将这个创建商店转换为基于承诺的商店



我的应用程序最初是从本地存储加载数据,现在我正在尝试使用firebase。Firebase总是倾向于回报承诺。所以我正在尝试将商店转换为firebase return商店。

这是的原件

export const loadState = () => {
const state: AppState = getDefaultState();
VALID_LABS.forEach(labId => {
state.labs[labId] = getDefaultLabState();
STORAGE_CONFIG.forEach(storageField => {
const { statePath, storageKey, defaultValueFn } = storageField;
const loadedValue = getFromLocalStorage(
labId,
storageKey,
defaultValueFn()
);
cachedValues[`${labId}:${storageKey}`] = loadedValue;
set(state, `labs.${labId}.${statePath}`, loadedValue);
});
});
return state as AppState;
};

const store = createStore(rootReducer, loadState(), applyMiddleware(thunk));
store.subscribe(
throttle(() => {
saveState(store.getState());
}, 500)
);

正如你们所看到的,我正在使这个过程顺利进行。但当我开始使用firebase时,问题就出现了。

我的loadState变成这样。

export const loadState = (): AppState => {
if (firebase.auth().currentUser.uid) {
let userId = firebase.auth().currentUser.uid;
return firebase
.database()
.ref('/users/' + userId)
.once('value')
.then(function(snapshot) {
return snapshot.val() as AppState;
}).catch((err) => {
console.error(err)
})
}
};

因此,我还需要转换store以接受从新的loadState返回的promise。我不知道如何转换,因为我也在使用applyMiddleWare(thunk)

let saveState: (state: AppState) => void
    ;
let loadState: () => AppState;
if(firebase.auth().currentUser){
loadState = loadStateFirebase;
saveState = saveStateFirebase;
}else{
loadState = loadStateLocalStorage;
saveState = saveStateLocalStorage;
}
// call loadstate then data,pass it in as second para to appstate store
const store = createStore(rootReducer, loadState(), applyMiddleware(thunk));
store.subscribe(
throttle(() => {
saveState(store.getState());
}, 500)
);

有人能帮我吗

首先,有一个小错误,您可能应该在catch块的末尾使用throw err,如果您不这样做,错误将被视为已处理,从catch返回的任何内容都将被认为是promise的值。在这种情况下,它是undefined,因此如果发生错误,loadState将解析为未定义的,而不是AppState对象,这可能会导致一些问题,但这取决于您,也许您有其他计划来处理此

无论如何,promise的问题是,一旦一个函数开始使用它,其他所有函数也必须使用它。更简单的选择是在异步函数中创建存储:

function createStore() {
return loadState()
.then(state => {
const store = createStore(rootReducer, state, applyMiddleware(thunk))
// Either subscribe to store here
return store
})
}
const storePromise = createStore()
// or here
/* storePromise.then(store => store.subscribe(...))

或使用async/await

async function createStore() {
const state = await loadState()
return createStore(rootReducer, state, applyMiddleware(thunk))
}
const storePromise = createStore()

很难判断这是否适合您的应用程序,根据标签判断,您正在使用react,因此您可能需要添加额外的逻辑来加载此存储,例如编写一个StoreProvider并用它包装您的App

function StoreProvider({ children }: { children?: ReactNode }) {
const [store, setStore] = useState<Store<AppState> | null>(null)
useEffect(() => {
createStore().then(setStore)
}, [])
if(!store) return <Loading /> // or whatever
return <Provider store={store}>{children}</Provider>
}

这对你来说可能很好,也可能不好。通常情况下,这不是很好,因为当firebase正在加载其内容时,您的应用程序无法渲染。另一种解决方案是在一开始就用空状态初始化存储,呈现应用程序中不需要firebase人员的部分,并让其他人等待加载,您可以使用thunks,或者创建三个操作LOAD_STORE/REQUESTLOAD_STORE/SUCCESSLOAD_STORE/ERROR,并使应用程序以适当的方式呈现。你可以创建一个系统,在加载时对一些需要存储的操作进行排队,并在完成后立即自动执行,这里有很大的创造力和挫败感,设计异步存储是一个相当大的挑战,你需要根据你的应用程序需要来决定如何执行

最新更新