Я создал базовое приложение с NextJS, которое извлекает данные из API как на стороне сервера, так и на стороне клиента.
Для этого я создал действия и редуктор.Проблема в том, что, когда я попадаю на страницу, она приходит с сервера без состояния (я могу наблюдать это на странице-источнике), но после второй клиентской работы и получения данных.Сразу после того, как страница попадает в браузер, я вижу журнал ответов на консоли сервера.Это означает, что сервер не ожидает ответа и не может создать с ним состояние.
Я прочитал и попробовал так много решений для достижения асинхронных / ожидающих событий от stackoverflow, но ни одно из них не работает для меня, или я не смог реализовать егоправильно.
Вот файлы, которые я использую.Я думаю, что этого будет достаточно, но если вам нужна дополнительная информация, я могу поделиться другими частями.
Спасибо.
getCurrencyAction.js
import { actionTypes } from './action-types';
import fetch from 'isomorphic-unfetch'
export function fetchCurrency() {
return dispatch => {
dispatch(apiCurencyFetch());
return fetch("/currency-api")
.then(handleErrors)
.then(res => res.json())
.then(json => {
dispatch(apiCurencySuccess(json));
return json;
})
.catch(error => dispatch(apiCurencyError(error)));
};
}
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
export const apiCurencyFetch = () => dispatch => {
return dispatch({
type: actionTypes.API_CURRENCY_FETCH
})
}
export const apiCurencySuccess = (data) => dispatch => {
return dispatch({
type: actionTypes.API_CURRENCY_SUCCESS,
payload: {data}
})
}
export const apiCurencyError = (err) => dispatch => {
return dispatch({
type: actionTypes.API_CURRENCY_ERROR,
payload: {err}
})
}
getCurrencyReducer.js
import { actionTypes } from '../actions/action-types';
const initialState = {
loading: false,
error: null,
data: []
}
export default function currencies(state = initialState, action) {
switch(action.type) {
case actionTypes.API_CURRENCY_FETCH:
return {
...state,
loading: true,
error: null
};
case actionTypes.API_CURRENCY_SUCCESS:
return {
...state,
loading: false,
data: action.payload.data
};
case actionTypes.API_CURRENCY_ERROR:
return {
...state,
loading: false,
error: action.payload.error,
};
default:
return state;
}
}
store.js
import { createStore, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunkMiddleware from 'redux-thunk'
import reducer from './reducers'
import { actionTypes } from './actions/action-types'
export function initializeStore (initialState = {}) {
return createStore(reducer, initialState, composeWithDevTools(applyMiddleware(thunkMiddleware)))
}
withReduxStore.js
import React from 'react'
import { initializeStore } from '../store'
const isServer = typeof window === 'undefined'
const __NEXT_REDUX_STORE__ = '__NEXT_REDUX_STORE__'
function getOrCreateStore (initialState) {
// Always make a new store if server, otherwise state is shared between requests
if (isServer) {
return initializeStore(initialState)
}
// Create store if unavailable on the client and set it on the window object
if (!window[__NEXT_REDUX_STORE__]) {
window[__NEXT_REDUX_STORE__] = initializeStore(initialState)
}
return window[__NEXT_REDUX_STORE__]
}
export default (App) => {
return class AppWithRedux extends React.Component {
static async getInitialProps (appContext) {
// Get or Create the store with `undefined` as initialState
// This allows you to set a custom default initialState
const reduxStore = getOrCreateStore()
// Provide the store to getInitialProps of pages
appContext.ctx.reduxStore = reduxStore
let appProps = {}
if (typeof App.getInitialProps === 'function') {
appProps = await App.getInitialProps(appContext)
}
return {
...appProps,
initialReduxState: reduxStore.getState()
}
}
constructor (props) {
super(props)
this.reduxStore = getOrCreateStore(props.initialReduxState)
}
render () {
return <App {...this.props} reduxStore={this.reduxStore} />
}
}
}
index.js
import { Component } from 'react';
import { connect } from "react-redux";
// Components
import { fetchCurrency } from '../actions'
import { Showcase, Pagebody } from '../sections/'
import Layout from '../layouts/default.js'
// Code
class Index extends Component {
constructor (props) {
super(props)
}
componentWillMount() {
this.props.dispatch(fetchCurrency());
}
render() {
return (
<Layout>
<Showcase />
<Pagebody />
</Layout>
)
}
}
export default connect()(Index);