React Router how to return 404 page in case of dynamic routes expecting a parameter?

时间:2018-05-13 22:03:08

标签: reactjs react-router react-router-v4 react-router-dom

Say I have the following route defined in a Switch:

<Switch>
    <Route path='/:pageId' component={Template} />
<Switch>

In the template I pass :pageId to the API and it returns the content for that page. It all works well, however the app crashes if I pass a :pageId value that does no exists (like I have no page with a slug "contact").

How can I make it redirect to a 404 page in this case so as to avoid the app crashing?

Thanks in advance.

2 个答案:

答案 0 :(得分:2)

由于您只是将可变页面ID传递给Route组件而没有专门命名每个路由,因此在服务器不返回任何内容的情况下,您将希望模板组件返回404页面。

在没有可用路径与给定路径匹配的情况下,Switch将采用直通组件,但只有在您使用特定的命名路径(即/users)时才会起作用,没有一个链接到变量页面名称的路由。

答案 1 :(得分:0)

一种可能的方法是利用React 16的错误边界。然后,您只要知道路由无效就可以抛出(只要它在渲染方法IIRC内)。

class RouteNotFoundError extends Error {
    constructor(...args) {
        super(...args)
        // extending Error is fickle in a transpiler world - use name check instead of instanceof/constructor
        this.name = "RouteNotFoundError"
    }
}

const RouteNotFoundBoundary = withRouter(
    class RouteNotFoundBoundary extends React.Component {
        constructor(props) {
            super(props)
            this.state = { routeNotFound: undefined }
        }
        componentWillReceiveProps(nextProps) {
            if (this.props.location !== nextProps.location) {
                this.setState({routeNotFound: false})
            }
        }
        componentDidCatch(e) {
            if (e.name === "RouteNotFoundError") {
                this.setState({routeNotFound: this.props.location.key})
            } else {
                throw e
            }
        }
        render() {
            if (this.state.routeNotFound === this.props.location.key) {
                return this.props.fallback || <div>Not found!</div>
            } else {
                return this.props.children
            }
        }
    }
)

const Template = props => {
    if (!allMyPages[props.match.params.pageId]) {
        throw new RouteNotFoundError()
    }

    return renderMyPage(allMyPages[props.match.params.pageId])
}

const Example = () => (
    <RouteNotFoundBoundary fallback={<div>Oh no!</div>}>
        <Switch>
            <Route path='/:pageId' component={Template}/>
        </Switch>
    </RouteNotFoundBoundary>
)

不确定这是否是一个好主意,但是当知道路径是否有效的代码路径不是呈现404页面的最佳位置时,它可能会简化某些情况。