react-router:动态内容未找到(404)?

时间:2017-01-20 22:30:23

标签: reactjs react-router universal isomorphic-javascript

react-router如何在通用应用中正确处理动态内容的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代码(用于服务器端 渲染)
  • 保持网址不变(我不想重定向)

我该怎么做?它接缝像一个非常标准的行为。我很惊讶没有找到任何例子...

修改
像我这样的接缝并不是唯一一个与之斗争的人。这样的事情会有很大帮助:https://github.com/ReactTraining/react-router/pull/3098
由于我的应用程序很快就不会上线,我决定等待下一个路由器版本提供的内容......

4 个答案:

答案 0 :(得分:1)

首先为onEnter回调创建一个中间件函数,这样对于redux promises来说这是可行的:

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

}

每当解析承诺失败时,react-router将自动寻找它可以为此端点呈现的下一个组件,在这种情况下是404组件。

因此,您不必使用replaceWith,并且您的网址会保留。

答案 1 :(得分:0)

如果您不使用服务器端渲染,则无法在页面呈现之前返回404。您需要在任何地方(在服务器上或通过客户端上的AJAX)检查用户是否存在。如果没有服务器端渲染,第一个是不可能的。

一种可行的方法是显示有关Promise错误的404页面。

答案 2 :(得分:0)

我在我正在制作的项目中尝试了我的解决方案,该项目使用服务器端渲染和反应路由器,它在那里工作,所以我会告诉你我做了什么。

创建一个功能,您可以在其中验证ID。如果ID有效,则返回带有适当组件的用户页面,如果ID无效,则返回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。

答案 3 :(得分:0)

在动态路径的情况下,您可以这样做,而不必更改当前路径。

只需导入 error404 组件并在状态中定义一个属性(未找到)以用于调节。

import React, { Component } from 'react';
import axios from 'axios';
import Error404 from './Error404';

export default class Details extends Component {
    constructor(props) {
        super(props)
        this.state = {
            project: {}, notfound: false
        }
    }

    componentDidMount() {
        this.fetchDetails()
    }

    fetchDetails = () => {
        let component = this;
        let apiurl = `/restapi/projects/${this.props.match.params.id}`;
        axios.get(apiurl).then(function (response) {
            component.setState({ project: response.data })
        }).catch(function (error) {
            component.setState({ notfound: true })
        })
    }

    render() {
        let project = this.state.project;
        return (
            this.state.notfound ? <Error404 /> : (
                <div>
                    {project.title}
                </div>
            )
        )
    }
}