TypeScriptを使用して、react-router documents で説明されているように<PrivateRoute>
を作成しようとしました。誰か助けてもらえますか?
react-routerドキュメントのprivateRoute:
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
fakeAuth.isAuthenticated ? (
<Component {...props}/>
) : (
<Redirect to={{pathname: '/login', state: { from: props.location }
}}/>
)
)}/>
)
以下は私のTypeScriptバージョンです(機能しません):
const PrivateRoute = (theProps: { path: string, component: React.SFC<RouteComponentProps<any> | undefined> | React.ComponentClass<RouteComponentProps<any> | undefined> }) => {
return <Route path={theProps.path} render={props => (
fakeAuth.isAuthenticated ? (
<React.Component {...theProps} /> <!-- **** It will raise error *** -->
) : (
<Redirect to={{
pathname: '/',
state: { from: props.location }
}} />
)
)} />
}
<React.Component {...thisProps} />
は正しくありません。エラーは次のとおりです:NodeInvocationException:inst.render is not a function TypeError:inst.render is not a function
おそらく、エラーはタイピングとレンダリングの暗黙的な戻りに関係しています。これを修正すると、最終的には次のようになります。
const PrivateRoute = ({component, isAuthenticated, ...rest}: any) => {
const routeComponent = (props: any) => (
isAuthenticated
? React.createElement(component, props)
: <Redirect to={{pathname: '/login'}}/>
);
return <Route {...rest} render={routeComponent}/>;
};
このコンポーネントは次のように使用できます。
<PrivateRoute
path='/private'
isAuthenticated={this.props.state.session.isAuthenticated}
component={PrivateContainer}
/>
上記のソリューションにはいくつかの欠点があります。 1つは、型の安全性を失うことです。
おそらくRoute
コンポーネントを拡張することをお勧めします。
import * as React from 'react';
import {Redirect, Route, RouteProps} from 'react-router';
export interface ProtectedRouteProps extends RouteProps {
isAuthenticated: boolean;
authenticationPath: string;
}
export class ProtectedRoute extends Route<ProtectedRouteProps> {
public render() {
let redirectPath: string = '';
if (!this.props.isAuthenticated) {
redirectPath = this.props.authenticationPath;
}
if (redirectPath) {
const renderComponent = () => (<Redirect to={{pathname: redirectPath}}/>);
return <Route {...this.props} component={renderComponent} render={undefined}/>;
} else {
return <Route {...this.props}/>;
}
}
}
したがって、次のようなコンポーネントを使用できます。
const defaultProtectedRouteProps: ProtectedRouteProps = {
isAuthenticated: this.props.state.session.isAuthenticated,
authenticationPath: '/login',
};
<ProtectedRoute
{...defaultProtectedRouteProps}
exact={true}
path='/'
component={ProtectedContainer}
/>
機能コンポーネントを作成したい場合は、非常によく似た方法で作成できます。これはReactルーター5でも機能します。
import * as React from 'react';
import { Redirect, Route, RouteProps } from 'react-router';
export interface ProtectedRouteProps extends RouteProps {
isAuthenticated: boolean;
isAllowed: boolean;
restrictedPath: string;
authenticationPath: string;
}
export const ProtectedRoute: React.FC<ProtectedRouteProps> = props => {
let redirectPath = '';
if (!props.isAuthenticated) {
redirectPath = props.authenticationPath;
}
if (props.isAuthenticated && !props.isAllowed) {
redirectPath = props.restrictedPath;
}
if (redirectPath) {
const renderComponent = () => <Redirect to={{ pathname: redirectPath }} />;
return <Route {...props} component={renderComponent} render={undefined} />;
} else {
return <Route {...props} />;
}
};
export default ProtectedRoute;
ユーザーが最初にアクセスしたいパスにユーザーをリダイレクトする場合は、パスを覚えておく必要があります。これにより、認証が成功した後にリダイレクトできます。次の答えはそれを通してあなたを導きます:
少しすっきりしたSFCフォームを引き続き使用できます。必要な小道具をRouteProps
と混ぜるだけです。
const PrivateRoute: React.SFC<RouteProps> = ({
component: Component,
...rest
}: {
component: React.ComponentType<RouteProps>;
}) => (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated
? <Component {...props} />
: <Redirect to="/login" />
}
/>
);