У меня есть существующее приложение React / Redux, которое в данный момент конвертируется в Next.
В файле _app я вызываю функцию asyc getinitialProps, и внутри этого im загружаю реквизиты, которые необходимо передать в App.
_app.js
import React from 'react'
import ReactDOM from 'react-dom'
import createHistory from 'history/createMemoryHistory'
import { syncHistoryWithStore, routerMiddleware } from 'react-router-redux'
import { initializeStore } from '../src/store'
import App from '../pages/index'
import { App as AppModel, User as UserModel } from '../src/models'
import * as Api from '../src/api'
import {makeStore} from '../src/redux/makeStore'
const dotenv = require('dotenv-safe')
// const manifest = require('./../dist/manifest.json')
if (typeof window !== "undefined" && window.ReactIntlLocaleData) {
Object.keys(window.ReactIntlLocaleData).forEach(lang => {
addLocaleData(window.ReactIntlLocaleData[lang]);
});
}
class IndexPage extends React.Component {
static async getInitialProps(context) {
global.CONFIG = {
...dotenv.config().required,
...dotenv.config().parsed,
}
global.historyUserConfirmationCallback = undefined
const history = createHistory({
getUserConfirmation: (message, callback) =>
global.historyUserConfirmationCallback(message, callback),
})
//see if window will work. Study actions push
history.listen((location, action) => {
window.scrollTo(0, 0)
if (location.pathname !== window.location.pathname) {
if (action === 'PUSH') {
window.history.pushState(null, null, location.pathname)
} else if (action === 'REPLACE') {
window.history.replaceState(null, null, location.pathname)
}
}
})
if(process.browser){
window.onpopstate = e => {
if (
history.entries[history.entries.length - 1] !== e.target.location.pathname
) {
history.push(e.target.location.pathname)
}
}
}
function getWindowState(){
if(process.browser){
return window.INITIAL_STAT
}
}
const store = initializeStore(getWindowState(), {
history: routerMiddleware(history),
})
const loggedInUser = Api.getCookie('token') && Api.getCookie('loggedInUser')
const loggedInUserLocale =
Api.getCookie('token') && Api.getCookie('loggedInUserLocale')
Api.session({
baseUrl: 'test',
})
if (loggedInUser) {
Api.session({
baseUrl: global.CONFIG.APP_API_URL,
access_token: Api.getCookie('token'),
})
store.dispatch(AppModel.actions.set('loggedInUser', loggedInUser))
store.dispatch(
AppModel.actions.set('loggedInUserLocale', loggedInUserLocale),
)
store.dispatch({
type: `${UserModel.ACTION_LOGIN}_FULFILLED`,
payload: { data: { username: loggedInUser, locale: loggedInUserLocale } },
})
}
if(process.browser){
history.push(window.location.pathname)
syncHistoryWithStore(history, store)
}
debugger;
return {store, history}
}
render() {
const {store, history} = this.props
return <App store={store} history={history} location={history.location.pathname} />
}
}
export default IndexPage
В файле store.js я экспортирую initializeStore следующим образом
createStore(
combineReducers(reducers),
initialState,
composeWithDevTools(
applyMiddleware.apply(null, Object.values(defaultMiddlewares)),
),
)
Я хочу передать store в. история пропадает без проблем. Но store - это всегда пустой объект. И это выдает следующую ошибку:
:3000/_next/static/runtime/main.js?ts=1571900711135:16480 Warning: Failed prop type: The prop `store.subscribe` is marked as required in `Connect(PromisedPropsHoc(BusinessProvider))`, but its value is `undefined`.
in Connect(PromisedPropsHoc(BusinessProvider)) (at ContextHoc.js:53)
in ContextHOC(Connect(PromisedPropsHoc(BusinessProvider))) (at ContextHoc.js:44)
in ComponentWithProvider (at _app.js:97)
in IndexPage
in Container (created by AppContainer)
in AppContainer
console.<computed> @ :3000/_next/static/runtime/main.js?ts=1571900711135:16480
:3000/_next/static/development/pages/_app.js?ts=1571900711135:311612 Uncaught TypeError: store.getState is not a function
Я пытался понять, почему это дольше всего. В чем проблема?
import React from 'react'
import PropTypes from 'prop-types'
import { Provider } from 'react-redux'
import { ThemeProvider } from '@material-ui/styles'
import { CssBaseline } from '@material-ui/core'
import { IntlProvider, addLocaleData } from 'react-intl'
import Routes from '../src/components/common/Routes'
import BusinessProvider from '../src/components/common/BusinessProvider'
import translations from '../lang/translations'
import theme from '../theme'
import 'react-image-lightbox/style.css'
import {makeStore} from '../src/redux/makeStore'
const App = ({ loggedInUserLocale, store, location, history, context }) => {
// Set the default locale
let locale = 'en';
// Check whether the logged in user has provided a locale
if (loggedInUserLocale !== undefined && loggedInUserLocale in translations) {
locale = loggedInUserLocale;
}
console.log("index page store")
debugger;
// Replace _ with - as _ is not part of a valid tag https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/getCanonicalLocales#Examples
const structuredLocale = locale.replace('_', '-');
const translation = translations[locale]
addLocaleData(translation.localeData)
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Provider store={store} id="App">
<IntlProvider key={locale} locale={structuredLocale} messages={translation.messages}>
<BusinessProvider>
<Routes
location={location}
history={history}
context={context}
/>
</BusinessProvider>
</IntlProvider>
</Provider>
</ThemeProvider>
)
}
App.propTypes = {
// eslint-disable-next-line react/forbid-prop-types
store: PropTypes.object.isRequired,
// eslint-disable-next-line react/forbid-prop-types
history: PropTypes.object,
// eslint-disable-next-line react/forbid-prop-types
context: PropTypes.object,
// eslint-disable-next-line react/forbid-prop-types
location: PropTypes.string,
}
App.defaultProps = {
location: '/',
history: {},
context: {},
}
export default BusinessProvider.provide()(App)