首页 > 解决方案 > getInitialProps 中的下一个 JS 代码在页面重新加载后不执行

问题描述

我正在将 NextJS 集成到我的 React 应用程序中。我遇到了一个问题,在页面重新加载或打开直接链接(例如 somehostname.com/clients)时我没有执行,但是如果我使用from它getInitialProps打开这个页面效果很好。我真的不明白它为什么会发生以及如何解决它。我已经遇到过类似的问题,但没有找到任何适合我的解决方案。<Link>next/link

客户页面代码:

import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { ClientsTable } from '../../src/components/ui/tables/client-table';
import AddIcon from '@material-ui/icons/Add';
import Fab from '@material-ui/core/Fab';
import { AddClientModal } from '../../src/components/ui/modals/add-client-modal';
import CircularProgress from '@material-ui/core/CircularProgress';
import { Alert } from '../../src/components/ui/alert';
import { Color } from '@material-ui/lab/Alert';
import { AppState } from '../../src/store/types';
import { thunkAddClient, thunkGetClients } from '../../src/store/thunks/clients';
import { SnackbarOrigin } from '@material-ui/core';
import { IClientsState } from '../../src/store/reducers/clients';
import { NextPage } from 'next';
import { ReduxNextPageContext } from '../index';
import { PageLayout } from '../../src/components/ui/page-layout';

const Clients: NextPage = () => {
  const [addClientModalOpened, setAddClientModalOpened] = useState<boolean>(false);
  const [alertType, setAlertType] = useState<Color>('error');
  const [showAlert, setAlertShow] = useState<boolean>(false);
  const alertOrigin: SnackbarOrigin = { vertical: 'top', horizontal: 'center' };

  const dispatch = useDispatch();
  const { clients, isLoading, hasError, message, success } = useSelector<AppState, IClientsState>(state => state.clients);

  useEffect(() => {
    if (success) {
      handleAddModalClose();
    }
  }, [success]);

  useEffect(() => {
    checkAlert();
  }, [hasError, success, isLoading]);

  function handleAddModalClose(): void {
    setAddClientModalOpened(false);
  }

  function handleAddClient(newClientName: string): void {
    dispatch(thunkAddClient(newClientName));
  }

  function checkAlert() {
    if (!isLoading && hasError) {
      setAlertType('error');
      setAlertShow(true);
    } else if (!isLoading && success) {
      setAlertType('success');
      setAlertShow(true);
    } else {
      setAlertShow(false);
    }
  }

  return (
    <PageLayout>
      <div className='clients'>
        <h1>Clients</h1>

        <div className='clients__add'>
          <div className='clients__add-text'>
            Add client
          </div>
          <Fab color='primary' aria-label='add' size='medium' onClick={() => setAddClientModalOpened(true)}>
            <AddIcon/>
          </Fab>

          <AddClientModal
            opened={addClientModalOpened}
            handleClose={handleAddModalClose}
            handleAddClient={handleAddClient}
            error={message}
          />
        </div>

        <Alert
          open={showAlert}
          message={message}
          type={alertType}
          origin={alertOrigin}
          autoHideDuration={success ? 2500 : null}
        />

        {isLoading && <CircularProgress/>}

        {!isLoading && <ClientsTable clients={clients}/>}

      </div>
    </PageLayout>
  );
};

Clients.getInitialProps = async ({ store }: ReduxNextPageContext) => {
  await store.dispatch(thunkGetClients());
  return {};
};

export default Clients;

thunkGetClients()

export function thunkGetClients(): AppThunk {
  return async function(dispatch) {
    const reqPayload: IFetchParams = {
      method: 'GET',
      url: '/clients'
    };

    try {
      dispatch(requestAction());

      const { clients } = await fetchData(reqPayload);

      console.log(clients);

      dispatch(getClientsSuccessAction(clients));

    } catch (error) {
      dispatch(requestFailedAction(error.message));
    }
  };
}

_app.tsx 代码

import React from 'react';
import App, { AppContext, AppInitialProps } from 'next/app';

import withRedux from 'next-redux-wrapper';
import { Provider } from 'react-redux';
import { makeStore } from '../../src/store';
import { Store } from 'redux';

import '../../src/sass/app.scss';
import { ThunkDispatch } from 'redux-thunk';

export interface AppStore extends Store {
  dispatch: ThunkDispatch<any, any, any>;
}

export interface MyAppProps extends AppInitialProps {
  store: AppStore;
}

export default withRedux(makeStore)(
  class MyApp extends App<MyAppProps> {
    static async getInitialProps({
                                   Component,
                                   ctx
                                 }: AppContext): Promise<AppInitialProps> {
      const pageProps = Component.getInitialProps
        ? await Component.getInitialProps(ctx)
        : {};

      return { pageProps };
    }

    render() {
      const { Component, pageProps, store } = this.props;

      return (
        <>
          <Provider store={store}>
            <Component {...pageProps} />
          </Provider>
        </>
      );
    }
  }
);

寻求您的建议和帮助。不幸的是,我自己找不到解决方案。

标签: reactjsreact-reduxnext.jsserver-side-rendering

解决方案


这就是 Next.js 的工作方式,它在服务器getInitialProps中的第一个页面加载(重新加载或外部链接)时运行,并且使用它导航到的其余页面将在客户端上运行此方法。Link

这样做的原因是允许 Next.js 网站具有“本机”SEO 版本。


推荐阅读