【问题标题】:How to convert this create store with thunk to a promise based?如何将此创建商店与 thunk 转换为基于承诺的?
【发布时间】:2021-01-15 00:37:38
【问题描述】:

我的应用程序最初是从本地存储加载数据,现在我正在尝试使用 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)
);


const reactReduxFirebaseProps = {
  firebase,
  config: {},
  dispatch: store.dispatch,
};


ReactDOM.render(
  <Provider store={store}>
    <AmplitudeProvider {...amplitudeProps}>
      <ReactReduxFirebaseProvider {...reactReduxFirebaseProps}>
        <Router>
          <App />
        </Router>
      </ReactReduxFirebaseProvider>
    </AmplitudeProvider>
  </Provider>,
  document.getElementById('root')
);

谁能帮帮我

【问题讨论】:

    标签: reactjs typescript firebase


    【解决方案1】:

    然后 thunk 中间件仅适用于操作。所以基本上一个中间件会接受所有的动作并返回计算出的新状态。这与createStore 函数无关。 商店创建过程,一般来说,是一种同步的方式。

    但是您可以为您的Provider 传递一个默认的store 对象,之后,当异步firebase 调用返回时,您可以重新初始化整个状态。 我认为你可以做得更好。当您的App.js 执行组件onInit 生命周期时,只需调度一个操作。并在一个 thunk 动作中执行逻辑。 例如:

    //--- rest of the app.js
    
      useEffect( () => {
        dispatch(getUser())
      } , [dispatch]);
      
    // --- do the initialization only once, when the component loads
    
    
    //--- the action
    
    export const getUser = createAsyncThunk('GET_USER', async () => {
     if (firebase.auth().currentUser.uid) {
        let userId = firebase.auth().currentUser.uid;
        const snapshot = await firebase
          .database()
          .ref('/users/' + userId)
          .once('value');
        return snapshot.val() as AppState;
      } else {
        throw Erro('NO LOGGED IN USER!');
      }
    })
    

    你可以在你的reducer中导入这个动作,你可以得到这样的值:

    const reducer = (state, action) => {
    
        switch(action.type){
          case getUser.fulfilled:
    
          return {
            ...state,
            user: action.payload
          }
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      让你的 loadState 函数返回 Promise 类型

      export const loadState = (): Promise<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)
            })
        }
      };
      

      当你想使用它时

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

      【讨论】:

      • 回答问题。当我根据您的回答更改代码时。我收到此错误Cannot find name 'store' 是因为我们在匿名函数中删除存储吗?
      • 这没有意义。 store is undefined 可能有意义,但找不到 store 没有意义。尝试检查括号。
      • ?不是声明function (appstate:any) {const store = ...make store 只在这个函数内部可用吗?
      • 是的,它将使商店仅在该功能中可用。如果您从函数中访问它,那么它将失败。还要尝试在该函数中编写所有代码,因为它是异步的,因此如果您在函数之外编写代码,则很有可能无法初始化存储。
      • 最后一件事,为您的患者提供 Ty。你能再回顾一下我的问题吗?还有 2 种情况,我使用 store store.dispatch & 在渲染内 &lt;Provider store={store}&gt; 。你的建议是我在函数里面写那些?
      猜你喜欢
      • 2021-03-02
      • 2021-01-27
      • 1970-01-01
      • 2017-07-07
      • 2020-08-17
      • 2017-04-28
      • 1970-01-01
      • 2015-02-25
      相关资源
      最近更新 更多