【问题标题】:How to convert this create store to a promise based?如何将此创建商店转换为基于承诺的?
【发布时间】:2021-03-02 14:42:52
【问题描述】:

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

这是原版

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)
);

谁能帮帮我

【问题讨论】:

    标签: reactjs typescript firebase firebase-realtime-database


    【解决方案1】:

    首先,有一个小错误,你可能应该在你的catch块末尾throw err,如果你不这样做,错误将被视为已处理,并且从catch返回的任何内容都将被视为承诺的价值。在这种情况下它是undefined,所以如果发生错误,loadState 将解析为 undefined 而不是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 或创建三个操作 @ 987654335@, LOAD_STORE/SUCCESS, LOAD_STORE/ERROR 并让您的应用程序以适当的方式呈现。您也许可以创建一个系统,在加载时将一些需要存储的操作排队,并在完成后立即自动执行它们,这里有很多创意和挫折的空间,设计异步存储是一个相当大的挑战,您需要根据你的应用需求决定你想怎么做

    【讨论】:

      猜你喜欢
      • 2021-01-15
      • 2021-01-27
      • 1970-01-01
      • 2017-07-07
      • 2020-08-17
      • 2017-04-28
      • 1970-01-01
      • 2015-02-25
      相关资源
      最近更新 更多