2017-01-20 7 views
7

Как может react-router правильно обрабатывать 404 страницы для динамического контента в универсальном приложении?Реактивный маршрутизатор: не найден (404) для динамического содержимого?

Предположим, я хочу отобразить страницу пользователя с таким маршрутом, как '/user/:userId'. Я бы конфиг так:

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

Если я прошу /user/valid-user-id, я получаю страницу пользователя.

Если я прошу /foo, я получаю правильный 404.

Но что, если я прошу /user/invalid-user-id. При получении данных для пользователя я пойму, что этого пользователя не существует. Таким образом, правильная вещь, чтобы сделать швы быть:

  • Выводит 404 страницы
  • Вернуть код 404 HTTP (для серверной стороны рендеринга)
  • Keep URL-адреса, как это (я не хочу перенаправление)

Как это сделать? Это похоже на стандартное поведение. Я удивлен, что не найти ни одного примера ...

Edit:
Швы, как я не единственный, кто с ним бороться. Нечто подобное помогло бы много: https://github.com/ReactTraining/react-router/pull/3098
Поскольку мое приложение не будет идти жить в ближайшее время, я решил подождать, чтобы увидеть, что следующий маршрутизатор реагировать-версия может предложить ...

+1

Как вы извлекаете данные пользователя? Я думаю, что код будет неотъемлемой частью ответа, который вы ищете. –

+0

@KeesvanLierop Я использую redux. Таким образом, я получил бы ударное действие, возвращающее обещание. Ошибка, возвращенная обещанием, указывает на то, что данный userId не существует. По умолчанию это действие будет инициировано моим компонентом UserPage. Но, возможно, имеет смысл сделать это до фактического рендеринга компонента. Я не уверен ... Но я открыт для предложений, чтобы он работал с реактивным маршрутизатором ... –

ответ

0

Если вы не используя рендеринг на стороне сервера, возврат 404 до того, как страница будет отображаться, будет невозможна. Вам нужно будет проверить наличие пользователя где-нибудь в любом случае (на сервере или через AJAX на клиенте). Первое не было бы возможным без рендеринга на стороне сервера.

Одним из жизнеспособных подходов было бы показать страницу 404 об ошибке обещания.

+0

На самом деле я в порядке с отображением страницы для моего 404. Это всего лишь компонент, связанный с маршрутом, который должен не будет оказано. Я мог бы использовать обратный вызов маршрута 'onEnter', выполнить здесь запрос, а затем вызвать' replaceWith', если пользователь не существует. Но это не так, потому что это перенаправит пользователя на другой URL. BTW Я фактически делаю рендеринг на стороне сервера, поэтому я ищу универсальное решение. –

1

Прежде создать функцию промежуточного программного обеспечения для onEnter обратного вызова, так что это выполнимо для 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> 

Сейчас в этой onEnter функции вы можете работать непосредственно с Redux магазин. Таким образом, вы можете отправить действие, которое либо будет успешным, либо неудачным. Пример:

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() 
       }) 
     }) 
    } 

} 

Всякий раз, когда решительность обещание Теперь не удается, реагировать-маршрутизатор автоматически ищет следующий компонент, что он может оказать для этой конечной точки, которая в данном случае является 404 компонентой.

Таким образом, вам не нужно будет использовать replaceWith, и ваш URL-адрес будет сохранен.

0

Я пробовал свое решение в проекте, который я создаю, который использует серверную визуализацию и реагирующий маршрутизатор, и он работает там, поэтому я расскажу вам, что я сделал.

Создайте функцию, в которой вы будете проверять идентификатор. Если идентификатор действителен, то верните его с помощью страницы пользователя с соответствующим компонентом, если идентификатор недействителен, верните страницу с 404.

Смотрите пример:

// 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> 

Это должно работать с боковым сервера визуализации, как это было в моем project. Он не использует Redux.

+1

Спасибо, но может ли эта стратегия обрабатывать асинхронную проверку идентификатора? –

+0

@TomEsterez Я не знаю, я этого не пробовал, но 'route' получает значение, возвращаемое из ValidateID, поэтому, вероятно, не имеет значения, является ли идентификатор синхронным или асинхронным. –