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