Nextjs不在服务器端通过api调用等待初始状态

时间:2018-10-17 17:52:20

标签: javascript api redux next.js ssr

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

0 个答案:

没有答案