useSelector не работает, если хранилище явно не импортировано - PullRequest
0 голосов
/ 06 января 2020

У меня проблемы с useSelector хуком в приложении Гэтсби. js. Ловушка не может достичь значения store в Redux, если store явно не экспортирован из файла установки Redx и импортирован в файл компонента. Похоже, что <Provider> недоступно (?).

Ошибка: ошибка при выборе состояния хранилища: невозможно прочитать свойство 'user' из неопределенного

Я думаю, что я несколько испортил настройку redux или gatsby-browser // ssr, но я не знаю, как именно ... Любая помощь будет признательна.

// App.js

import React from 'react'
import { useSelector, useDispatch } from 'react-redux'

import { store } from '../store/ReduxWrapper' // <-- store needs to be imported to be accessible ?!

import { loadFirebaseInitialize } from '../store/app'
import AuthenticatedApp from '../containers/AuthenticatedApp'
import UnauthenticatedApp from '../containers/UnauthenticatedApp'

const App = () => {
 const dispatch = useDispatch()
 const firebase = useSelector(store => store.app.firebase) // <-- store is undefined unless explicitely    imported
 const user = useSelector(store => store.auth.user) // <-- store is undefined unless explicitely    imported

 if (!firebase) {
   dispatch(loadFirebaseInitialize())
   return (
     <div>
       <p>Loading firebase</p>
     </div>
   )
 } else {
   return user ? <AuthenticatedApp /> : <UnauthenticatedApp />
 }
}

export default App

// ReduxWrapper.js

import React from 'react'
import { Provider } from 'react-redux'
import { applyMiddleware, createStore } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from '.';

export const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
)

export default ({ element }) => (
  <Provider store={store}>{element}</Provider>
);

// gatsby-browser.js / gatsby-ssr.js

export { default as wrapRootElement } from './src/store/ReduxWrapper'

РЕДАКТИРОВАТЬ : добавление дополнительного кода, относящегося к избыточному:

// index.js
import { combineReducers } from 'redux';
import app from './app';
import auth from './auth';

export default combineReducers({ app, auth });

// auth.js

// to get state from a sibling ('app.js') store
import { store } from '../store/ReduxWrapper' 

const initialState = {
  isAuthenticated: false,
  isAuthPending: false,
  error: null,
  user: null,
}

const AUTH_REQUEST_INITIALIZE = 'AUTH_REQUEST_INITIALIZE'
const AUTH_REQUEST_SUCCESS = 'AUTH_REQUEST_SUCCESS'
const AUTH_REQUEST_ERROR = 'AUTH_REQUEST_SUCCESS'
const AUTH_LOGOUT = 'AUTH_LOGOUT'

export const authRequestInitialize = () => ({
  type: AUTH_REQUEST_INITIALIZE,
})

export const authRequestSuccess = user => ({
  type: AUTH_REQUEST_SUCCESS,
  user,
})

export const authRequestError = error => ({
  type: AUTH_REQUEST_ERROR,
  error,
})

export const authLogin = ({ email, password }) => dispatch => {
  const { firebase } = store.getState().app
  if (firebase) {
    dispatch(authRequestInitialize())
    firebase
      .auth()
      .signInWithEmailAndPassword(email, password)
      .then(user => console.log(`user`, user) || dispatch(authRequestSuccess(user)))
      .catch(error => console.log(`authError`, error) || dispatch(authRequestError(error)))
  }
}

export const authLogout = () => dispatch => {
  const { firebase } = store.getState().app
  if (firebase) {
    firebase.auth().signOut().then(
      res => dispatch({ type: AUTH_LOGOUT })
    )  
  }
}

export default (state = initialState, action) => {
  switch (action.type) {
    case AUTH_REQUEST_INITIALIZE:
      return { ...state, isAuthPending: true }
    case AUTH_REQUEST_SUCCESS:
      return { ...state, user: action.user }
    case AUTH_REQUEST_ERROR:
      return { ...state, error: action.error }
    case AUTH_LOGOUT:
      return { ...state, user: null }
    default:
      return state
  }
}

//app.js

import getFirebase from '../firebase'

const initialState = {
  firebase: null,
  isFirebaseLoading: false,
}

const LOAD_FIREBASE_INITIALIZE = 'LOAD_FIREBASE_INITIALIZE'
const LOAD_FIREBASE_SUCCESS = 'LOAD_FIREBASE_SUCCESS'
const LOAD_FIREBASE_ERROR = 'LOAD_FIREBASE_ERROR'

export const loadFirebaseInitialize = () => {
  return dispatch => {
    const app = import('firebase/app')
    const auth = import('firebase/auth')
    const firestore = import('firebase/firestore')

    Promise.all([app, auth, firestore])
      .then(values => {
        const firebase = getFirebase(values[0])
        dispatch(loadFirebaseSuccess(firebase))
      })
      .catch(error => dispatch(loadFirebaseError(error)))
  }
}

export const loadFirebaseSuccess = firebaseObj => ({
  type: LOAD_FIREBASE_SUCCESS,
  firebaseObj,
})

export const loadFirebaseError = error => ({
  type: LOAD_FIREBASE_ERROR,
  error,
})

export default (state = initialState, action) => {
  switch (action.type) {
    case LOAD_FIREBASE_INITIALIZE:
      return { ...state, isFirebaseLoading: true }
    case LOAD_FIREBASE_SUCCESS:
      return {
        ...state,
        isFirebaseLoading: false,
        firebase: action.firebaseObj,
      }
    case LOAD_FIREBASE_ERROR:
      return { ...state, isFirebaseLoading: false, error: action.error }
    default:
      return state
  }
}

Ответы [ 2 ]

0 голосов
/ 14 января 2020

Как я выяснил, описанная выше проблема, вероятно, была вызвана ошибкой в ​​среде разработки gatsby - использование git bash вместо windows, казалось, решало ее (среди других проблем) Например, реагирующие крюки не работают должным образом.

0 голосов
/ 14 января 2020

Как я вижу, вы не используете этот код:

export default ({ element }) => (
  <Provider store={store}>{element}</Provider>
);

Оберните ваше приложение в это, и вы сможете получить доступ к магазину, прямо сейчас у приложения нет доступа к магазину.

...