簡體   English   中英

使用React Router 4預取數據

[英]Prefetch data with React Router 4

我正在嘗試遷移到React Router的v4,並且卡住了預取數據。 我們過去具有匹配功能的最新版本。

返回的參數之一是renderProps,但是現在我不能使用match,所以我不知道如何預取數據。 文檔顯示了如何加載數據,但不適用於我,因為我正在使用新版本的react-router-redux同步存儲。

這是客戶端的代碼:

return (
  <MuiThemeProvider muiTheme={letgoMuiTheme}>
    <Provider store={store}>
      <IntlProvider>
        { routes(history, store) }
      </IntlProvider>
  </Provider>
</MuiThemeProvider>
);

路線:

export default function routes(history) {
  return (
    <ConnectedRouter history={history}>
      <Switch>
        <Route exact path="/" component={App} />
        <Route path="/:lang/chat" component={Chat} />
        ...
        <Route path="*" component={NotFound} status={404} />
      </Switch>
    </ConnectedRouter>
  );
}

服務器:

if (context.url) {
  res.redirect(302, redirectLocation.pathname + redirectLocation.search);
} else {
  const render = () => {
    const body = renderToString(
      <StaticRouter
        location={req.url}
        context={context}
      >
        <MuiThemeProvider muiTheme={muiTheme}>
          <Provider store={store}>
            <IntlProvider>
              { routes(history, store) }
            </IntlProvider>
          </Provider>
        </MuiThemeProvider>,
      </StaticRouter>
    );

    res.setHeader('content-language', locale);
    res.render('index', {
      head,
      body,
      locale,
      state: stringState,
      ...
    });
  };

  Promise.all(
    prefetchData(renderProps, store),
  )
  .then(render)
  .catch(prefetchError => next(prefetchError));
}

那是我的舊服務器文件:

    match({ history, routes, location: req.url }, (error, redirectLocation, renderProps) => {
      if (error) {
        throw error;
      } else if (redirectLocation) {
        res.redirect(302, redirectLocation.pathname + redirectLocation.search);
      } else if (renderProps) {
        // Render react components once store is initializaed and return HTTP response
        const render = () => {
          const body = renderToString(
            <MuiThemeProvider muiTheme={muiTheme}>
              <Provider store={store}>
                <IntlProvider>
                  <RouterContext {...renderProps} />
                </IntlProvider>
              </Provider>
            </MuiThemeProvider>,
          );

          res.setHeader('content-language', locale);
          res.render('index', {
            head,
            newrelicScript,
            body,
            locale,
            state: stringState,
            ...
          });
        };

        // Fetch components data and render HTML (no matter the fetch results
        // we need to render something)
        Promise.all(
          prefetchData(renderProps, store),
        )
        .then(render)
        .catch(prefetchError => next(prefetchError));
      } else {
        logger.warning('Ops !!! We should never arrive here :(');
        next();
      }
    });

並預取數據:

export const prefetchData = (renderProps, store) => {
  const { components, params } = renderProps;
  const { dispatch } = store;
  const state = store.getState();
  const extractWrappedComponent = (component) => {
    if (component.WrappedComponent) {
      return extractWrappedComponent(component.WrappedComponent);
    }
    return component;
  };

  return components
    .filter(component => component !== undefined)
    // Get component, be aware if they are wrapped by redux connect or intl.
    .map(component => extractWrappedComponent(component))
    // Get the fetchData method of each component
    .map(component => component.fetchData)
    .filter(fetchData => fetchData !== undefined)
    // Invoke each fetchData to initialize the redux state.
    .map(fetchData => fetchData(state, dispatch, params));
};

經過研究,我找到了適合我的解決方案。 這是幫助器(之前是prefetchData)。 matchPath來自react-router-dom

export const getRouteData = (routesArray, url, store) => {
  const { dispatch } = store;
  const state = store.getState();
  const extractWrappedComponent = (component) => {
    if (component.WrappedComponent) {
      return extractWrappedComponent(component.WrappedComponent);
    }
    return component;
  };

  return routesArray.map((route) => {
    const component = route.component;
    const extractedComponent = extractWrappedComponent(component);
    const match = matchPath(url, { path: route.path, exact: route.exact, strict: false });

    if (match) {
      if (extractedComponent.fetchData !== undefined) {
        extractedComponent.fetchData(state, dispatch, match.params);
      }
    }
  });
}

然后我稱之為:

getRouteData(routes, req.url, store);

路由是靜態路由

export const routes = [
  {
    path: '/',
    component: App
  },
  {
    path: '/:lang/chat',
    component: Chat
  }
  ...

我的服務器文件現在不匹配。 代替:

if (context.url) {
  res.redirect(302, context.url);
} else {
  const render = () => {
    const body = renderApp(req, muiTheme, store, history, context);

    res.render('index', {
      head,
      body,
      locale,
      ...
    });
  };

  Promise.all(
    getRouteData(routes, req.url, store),
  )
  .then(render)
  .catch(prefetchError => next(prefetchError));

RenderApp文件(沒有StaticRouter客戶端必須相同):

const renderApp = (req, muiTheme, store, history, context) => {
  const app = (
    <MuiThemeProvider muiTheme={muiTheme}>
      <Provider store={store}>
        <IntlProvider>
          <StaticRouter
            location={req.url}
            context={context}
          >
            { appRoutes(history) }
          </StaticRouter>
        </IntlProvider>
      </Provider>
    </MuiThemeProvider>
  );

  return renderToString(app);
};

appRoutes文件:

export default function appRoutes(history) {
  return (
    <ConnectedRouter history={history}>
      <div>
        {routes.map((route, key) => (
          <Route key={key} {...route} />
        ))}
      </div>
    </ConnectedRouter>
  );
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM