2017-01-20 14 views
7

W jaki sposób react-router prawidłowo obsługuje 404 strony dla zawartości dynamicznej w aplikacji Universal?react-router: Nie znaleziono (404) dla zawartości dynamicznej?

Załóżmy, że chcę wyświetlić stronę użytkownika z trasą taką jak '/user/:userId'. Chciałbym mieć takiego: config

<Route path="/"> 
    <Route path="user/:userId" component={UserPage} /> 
    <Route path="*" component={NotFound} status={404} /> 
</Route> 

Gdybym zażądać /user/valid-user-id, mam stronę użytkownika.

Gdybym zażądać /foo, dostaję właściwego 404.

Ale co jeśli żądania /user/invalid-user-id. Podczas pobierania danych dla użytkownika zdaję sobie sprawę, że ten użytkownik nie istnieje. Tak, poprawna rzeczą do zrobienia szwy być:

  • Wyświetlanie 404
  • Powrót kod 404 HTTP (na stronie serwera rendering)
  • utrzymać url jak jest (nie chcę przekierowanie)

Jak to zrobić? Szwy przypominają bardzo standardowe zachowanie. Jestem zaskoczony, że nie znaleźliśmy żadnego przykładu ...

Edit:
Szwy to, że nie jestem jedynym, do walki z nim. Coś takiego byłoby bardzo pomocne: https://github.com/ReactTraining/react-router/pull/3098
Jak moja aplikacja nie będzie żyć w najbliższym czasie, postanowiłem poczekać, aby zobaczyć co następna wersja reagować-router ma do zaoferowania ...

+1

Jak pobrać dane użytkownika? Myślę, że kod będzie zasadniczą częścią odpowiedzi, której szukasz. –

+0

@KeesvanLierop Używam redux. Tak więc miałbym akcję powracającą z obietnicą. Błąd zwracany przez obietnicę wskazywałby, że podany identyfikator użytkownika nie istnieje. Domyślnie akcja ta byłaby uruchamiana przez mój komponent UserPage. Ale może lepiej jest zrobić to przed faktycznym renderowaniem komponentu. Nie jestem pewien ... Ale jestem otwarty na sugestie, aby działał z routerem reagującym ... –

Odpowiedz

0

Jeżeli nie jesteś przy użyciu renderowania po stronie serwera, powrót 404 przed renderowaniem strony nie byłby możliwy. Będziesz musiał sprawdzić istnienie użytkownika w dowolnym miejscu (na serwerze lub za pośrednictwem AJAX na kliencie). Pierwsza nie byłaby możliwa bez renderowania po stronie serwera.

Jednym realnym podejściem byłoby pokazanie strony 404 o błędzie obietnicy.

+0

Właściwie nic mi nie jest z renderowaniem strony dla mojego 404. To tylko komponent związany z trasą, która powinna nie zostaną oddane. Mogę użyć wywołania zwrotnego "onEnter" trasy, wykonaj żądanie tutaj, a następnie wywołaj 'replaceWith', jeśli użytkownik nie istnieje. Ale tak się nie podoba, ponieważ przekieruje użytkownika do innego adresu URL. BTW w rzeczywistości robię renderowanie po stronie serwera, więc szukam uniwersalnego rozwiązania. –

1

Przede utworzyć funkcję middleware dla onEnter zwrotnego, tak, że jest to wykonalne dla obietnic Redux:

import { Router, Route, browserHistory, createRoutes } from "react-router"; 

function mixStoreToRoutes(routes) { 
    return routes && routes.map(route => ({ 
     ...route, 
     childRoutes: mixStoreToRoutes(route.childRoutes), 
     onEnter: route.onEnter && function (props, replaceState, cb) { 
      route.onEnter(store.dispatch, props, replaceState) 
       .then(() => { 
        cb(null) 
       }) 
       .catch(cb) 
     } 
    })); 
} 

const rawRoutes = <Route path="/"> 
    <Route path="user/:userId" component={UserPage} onEnter={userResolve.fetchUser} /> 
    <Route path="*" component={NotFound} status={404} /> 
</Route> 

Teraz w tym onEnter funkcji można pracować bezpośrednio z magazynu Redux. Możesz więc wysłać akcję, która zakończy się sukcesem lub zakończy się niepowodzeniem. Przykład:

function fetch(options) { 
    return (dispatch) => { 
     return new Promise((resolve, reject) => { 
      axios.get('<backend-url>') 
       .then(res => { 
        resolve(dispatch({type: `CLIENT_GET_SUCCESS`, payload: res.data})) 
       }) 
       .catch(error => { 
        reject(dispatch({type: `CLIENT_GET_FAILED`, payload: error})); 
       }) 
      } 
     }) 
    } 
} 

let userResolve = { 

    fetchUser: (dispatch, props, replace) => { 
     return new Promise((next, reject) => { 
      dispatch(fetch({ 
       user: props.params.user 
      })) 
       .then((data) => { 
        next() 
       }) 
       .catch((error) => { 
        next() 
       }) 
     }) 
    } 

} 

Ilekroć obietnica postanowienie nie teraz, reagują-router automatycznie szukać kolejnego składnika, który mógłby uczynić dla tego punktu końcowego, który w tym przypadku jest komponent 404.

Dzięki temu nie będziesz musiał używać replaceWith, a URL pozostanie zachowany.

0

Próbowałem mojego rozwiązania w projekcie, który robię, który używa Server Side Rendering i reaguje-router i działa tam, więc powiem ci co zrobiłem.

Utwórz funkcję, w której sprawdzisz identyfikator. Jeśli identyfikator jest ważny, a następnie zwróć stronę z użytkownikiem z odpowiednim komponentem, jeśli identyfikator jest nieprawidłowy, zwróć stronę 404.

Patrz przykład:

// Routes.jsx

function ValidateID(ID) { 
    if(ID === GOOD_ID) { 
     return (
      <Route path="/"> 
       <Route path="user/:userId" component={UserPage} /> 
       <Route path="*" component={NotFound} status={404} /> 
      </Route> 
     ); 
    } else { 
     return (
      <Route path="/"> 
       <Route path="user/:userId" status={404} component={Page404} /> 
       <Route path="*" component={NotFound} status={404} /> 
      </Route> 
     ); 
    } 

// Router.jsx

<Router route={ValidateID(ID)} history={browserHistory}></Router> 

To powinno działać z renderowania Server Side jak to miało miejsce w moim project. Nie używa Redux.

+1

Dzięki, ale czy ta strategia może obsługiwać sprawdzanie asynchroniczne identyfikatora? –

+0

@TomEsterez Nie wiem, nie próbowałem tego, ale 'route' zwraca wartość zwróconą przez ValidateID, więc prawdopodobnie nie ma znaczenia, czy ID jest synchroniczne czy asynchroniczne. –

Powiązane problemy