reactjs - 如何将此创建商店转换为基于承诺的?
问题描述
我的应用程序最初是从本地存储加载数据,现在我正在尝试使用 firebase。Firebase 总是倾向于返回一个承诺。所以我正在尝试将商店转换为 firebase 返回一个。
这是原来的
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
为接受promise
从新返回的loadState
. 我不知道如何转换它,因为我也在使用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)
);
有人能帮我吗
解决方案
首先,有一个小错误,你可能应该throw err
在你的 catch 块的末尾,如果你不这样做,错误将被视为已处理,并且返回的任何内容都catch
将被视为 promise 的值。在这种情况下它是undefined
,所以如果发生错误,loadState
将解析为
undefined 而不是AppState
object,这可能会导致一些问题,但这取决于你,也许你有其他计划如何处理这个
无论如何,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,因此您可能需要添加额外的逻辑来加载此商店,例如编写 aStoreProvider
并用它包装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
加载其内容时无法渲染。另一种解决方案是在开始时使用空状态初始化 store,渲染应用程序中不需要 firebase 人员的部分并让其他人等待它加载,您可以thunk
为此使用 s 或创建三个操作LOAD_STORE/REQUEST
,LOAD_STORE/SUCCESS
和LOAD_STORE/ERROR
make您的应用程序以适当的方式呈现。您也许可以创建一个系统,在加载时将一些需要存储的操作排队,并在完成后立即自动执行它们,这里有很多创意和挫折的空间,设计异步存储是一个相当大的挑战,您需要根据您的应用程序需求决定您想如何做
推荐阅读
- python - 如何下载 Python 的 graphics.py?
- ios - 根据所选行显示不同数据的 UIPICKERVIEW
- javascript - 触发事件后将查询字符串传递给 react-router 中的 url
- typescript - 如何让 npm 从 GitHub url 安装 typescript 依赖项?
- android - actionLayout 不显示在导航抽屉中
- android - 试图在列表视图的末尾加载更多项目
- batch-file - 检查驱动器是否有足够的空间进行备份
- android - 应用程序在模拟器上完美显示,但在设计预览中不显示?
- python - 如何从 colaboratory 下载此模型
- installshield - Installshield 2013 Installscript MSI:修复期间错误的 .msi 位置