この( reacttraining.com )サイトを見つけました。このサイトでは、react-routerをいくつかの例で説明しています。しかし、TypeScriptクラスでこれを行うことはできません。私がやりたいことは、独自のクラスを構築するためにRouteクラスを拡張することです。今のところ、次のサイトの例のように、認証用にTypeScriptで実装したいと思います。
const PrivateRoute = ({ component, ...rest }) => (
<Route {...rest} render={props => (
fakeAuth.isAuthenticated ? (
React.createElement(component, props)
) : (
<Redirect to={{
pathname: '/login',
state: { from: props.location }
}}/>
)
)}/>
)
何度も検索しましたが、実装する関数と、ネストされたルートに呼び出す型付きプロパティを説明しているサイトが見つかりませんでした。 ES6クラスも役に立ちます。ありがとうございます。
any
はまだ1つ残っていますが、ここまでが私のベストショットです:)
import * as React from "react"
import {Redirect, Route, RouteComponentProps, RouteProps} from "react-router-dom"
type RouteComponent = React.StatelessComponent<RouteComponentProps<{}>> | React.ComponentClass<any>
const AUTHENTICATED = false // TODO: implement authentication logic
export const PrivateRoute: React.StatelessComponent<RouteProps> = ({component, ...rest}) => {
const renderFn = (Component?: RouteComponent) => (props: RouteProps) => {
if (!Component) {
return null
}
if (AUTHENTICATED) {
return <Component {...props} />
}
const redirectProps = {
to: {
pathname: "/auth/sign-in",
state: {from: props.location},
},
}
return <Redirect {...redirectProps} />
}
return <Route {...rest} render={renderFn(component)} />
}
ジャッカの答え は私を助けてくれましたが、PrivateRoute
コンポーネントをreduxに接続するのに苦労しました。さらに、結果として得られるRoute
コンポーネントを抽象化して、機能するようにしました。 LoggedInRoute
、NotLoggedInRoute
、または一般にRoute
として、条件が満たされている場合はコンポーネントであることを示し、そうでない場合は指定された場所にリダイレクトします。
注:redux
4、_react-router-dom
_ 4およびTypeScript _2.9
_で記述されています。
_import * as H from 'history';
import * as React from 'react';
import { connect, MapStateToPropsParam } from 'react-redux';
import { Redirect, Route, RouteComponentProps, RouteProps } from 'react-router';
export interface ConditionalRouteProps extends RouteProps {
routeCondition: boolean;
redirectTo: H.LocationDescriptor;
}
export class ConditionalRoute extends React.Component<ConditionalRouteProps> {
public render() {
// Extract RouteProps without component property to rest.
const { component: Component, routeCondition, redirectTo, ...rest } = this.props;
return <Route {...rest} render={this.renderFn} />
}
private renderFn = (renderProps: RouteComponentProps<any>) => {
if (this.props.routeCondition) {
const { component: Component } = this.props; // JSX accepts only upprcase.
if (!Component) {
return null;
}
return <Component {...renderProps} />
}
return <Redirect to={this.props.redirectTo} />;
};
}
export function connectConditionalRoute<S>(mapStateToProps: MapStateToPropsParam<ConditionalRouteProps, RouteProps, S>) {
return connect<ConditionalRouteProps, {}, RouteProps, S>(mapStateToProps)(ConditionalRoute);
}
_
接続せずにConditionalRoute
コンポーネントを使用して、コンポーネントのローカル状態を使用することができます。例:
_interface RootState {
loggedIn: boolean;
}
export class Root extends React.Component<RootProps, RootState> {
/* skipped initialState and setState(...) calls */
public render() {
return (
<Switch>
<ConditionalRoute
path="/todos"
component={TodoPage}
routeCondition={this.state.loggedIn}
redirectTo="/login" />
<ConditionalRoute
path="/login"
component={LoginPage}
routeCondition={!this.state.loggedIn}
redirectTo="/" />
<Redirect to="/todos" />
</Switch>
);
}
}
_
または、ユーティリティ関数connectConditionalRoute<S>(...)
を使用してreduxストアを使用します。
_const loginRoute = '/login';
const todosRoute = '/todos';
const LoggedInRoute = connectConditionalRoute<RootState>(state => ({
redirectTo: loginRoute,
routeCondition: state.isLoggedIn,
}));
const NotLoggedInRoute = connectConditionalRoute<RootState>(state => ({
redirectTo: todosRoute,
routeCondition: !state.isLoggedIn
}));
const Root: React.SFC = () => (
<Switch>
<LoggedInRoute path="/todos" component={TodoPage} />
<NotLoggedInRoute path="/login" component={LoginPage} />
<Redirect to="/todos" />
</Switch>
);
_
提供されているサンプルの動作:権限のないユーザーが_/todos
_にアクセスすると、_/login
_にリダイレクトされ、権限のあるユーザーは_/login
_にアクセスし、_/todos
_にリダイレクトされます。 reduxストアのisLoggedIn
が変更されると、接続されているコンポーネントが更新され、ユーザーが自動的にリダイレクトされます。
同じものを探していました。質問は古いですが、おそらく誰かがまだそれを探しています。これが私が思いついたものです(react-router 4からすべてのタイプが適切に使用されています):
interface PrivateRouteProps extends RouteProps {
component: React.ComponentType<RouteComponentProps<any>> | React.ComponentType<any>
}
type RenderComponent = (props: RouteComponentProps<any>) => React.ReactNode;
export class PrivateRoute extends Route<PrivateRouteProps> {
render () {
const {component: Component, ...rest}: PrivateRouteProps = this.props;
const renderComponent: RenderComponent = (props) => (
AuthenticationService.isAuthenticated()
? <Component {...props} />
: <Redirect to='/login' />
);
return (
<Route {...rest} render={renderComponent} />
);
}
}
これが"react-router-dom": "^4.4.0-beta.6"
と"TypeScript": "3.2.2"
を使用した私の解決策です
import React, { FunctionComponent } from "react";
import {
Route,
Redirect,
RouteProps,
RouteComponentProps
} from "react-router-dom";
interface PrivateRouteProps extends RouteProps {
component:
| React.ComponentType<RouteComponentProps<any>>
| React.ComponentType<any>;
}
const PrivateRoute: FunctionComponent<PrivateRouteProps> = ({
component: Component,
...rest
}) => {
return (
<Route
{...rest}
render={props =>
true ? ( //put your authenticate logic here
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/signin"
}}
/>
)
}
/>
);
};
export default PrivateRoute;
any
を使用できます。
const PrivateRoute = ({component: Component, ...rest }: any) => (
<Route {...rest} render={PrivateRender(Component)} />
);
const PrivateRender = (Component: any) => {
return (props: any) => {
return <Component {...props}/>;
};
};
元のルートでcomponent
とrender
の両方のパラメーターを使用していたため、ここで提案された解決策は機能しませんでした。このソリューションでは、component
パラメータだけでなく、カスタムPrivateRouteでルートの構成を使用できます。
import * as React from 'react';
import {
Route,
Redirect,
RouteProps,
RouteComponentProps
} from "react-router-dom";
interface PrivateRouteProps extends RouteProps {
isAuthenticated: boolean;
}
export class PrivateRoute extends Route<PrivateRouteProps> {
render() {
return (
<Route render={(props: RouteComponentProps) => {
if(!this.props.isAuthenticated()) {
return <Redirect to='/login' />
}
if(this.props.component) {
return React.createElement(this.props.component);
}
if(this.props.render) {
return this.props.render(props);
}
}} />
);
}
}
例:
<PrivateRoute
path={'/dashboard'}
component={DashboardPage}
isAuthenticated={props.isAuthenticated}
/>
<PrivateRoute
path={'/checkout'}
isAuthenticated={props.isAuthenticated}
render={() => (
<CheckoutPage auth={props.auth} />
)}
/>