React:将 match.params 传递给 children
React: Passing match.params to children
我做了一个私有路由功能:
function PrivateRoute({ children, ...rest }) {
return (
<Route
{...rest}
render={({ location }) =>
isLoggedIn || isAccountVerified ? (
children
) : (
<Redirect
to={{
pathname: '/',
state: { from: location }
}}
/>
)
}
/>
);
}
现在我想要的是 Route
组件的任何 child 都可以访问其 :params
属性:
<PrivateRoute
path="/confirmed/:token"
isAccountVerified={isAccountVerified}>
<Confirmation />
</PrivateRoute>
这样我就可以在这个组件中使用它了:
class Confirmation extends Component {
constructor(props) {
super(props);
this.state = {
...somestate
};
}
componentDidMount() {
var { token } = this.props.token; // Use it here!!!!
axios
.get(`http://localhost:8016/users/confirmation/${token}`)
.then(response => {
console.log('response', response);
if (response.status === 200) {
this.setState({
responseMessage: response.data.msg
});
}
this.setState(() => ({ confirmedParam }));
})
.catch(
function(error) {
if (error.response.status === 404) {
this.setState({
responseMessage: error.response.data.msg,
error: true
});
return;
}
if (error.response.status === 400) {
this.setState({
responseMessage: error.response.data.msg,
error: true
});
return;
}
}.bind(this)
);
}
render() {
.....
}
如何实现?黑魔法很好...
20 年 3 月 22 日更新
客户端路由:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { logInUser, logOutUser } from '../store/reducers/users/index';
import { bindActionCreators } from 'redux';
import { Switch, Route, Redirect, withRouter } from 'react-router-dom';
import LinkNavWithLayout from './LinkNavWithLayout';
import Index from './home';
import Profile from './profile';
import Dashboard from './dashboard';
import ForgotPassword from './forgotPassword';
import ResetPassword from './resetPassword';
import Login from './login';
import Confirmation from './confirmation';
import { modalStateOn, modalStateOff } from '../store/reducers/ui/index';
import Register from './register';
class App extends Component {
static getInitialProps({
store,
isAccountVerified,
isLoggedIn,
logInUser,
logOutUser
}) {
console.log('store', store);
return { store, isAccountVerified, isLoggedIn, logInUser, logOutUser };
}
constructor(props) {
super(props);
}
render() {
const { isLoggedIn, isAccountVerified } = this.props;
console.log('isAccountVerified ', isAccountVerified);
console.log('this.props ', this.props);
let navBars = [
{ name: 'Home', path: '/' },
{ name: 'Profile', path: '/profile' },
{ name: 'Dashboard', path: '/dashboard' },
{ name: 'Log in', path: '/login' },
{ name: 'Register', path: '/register' }
];
// function PrivateRoute({ children, ...rest }) {
// return (
// <Route
// {...rest}
// render={({ location }) =>
// isLoggedIn || isAccountVerified ? (
// { ...children }
// ) : (
// <Redirect
// to={{
// pathname: '/',
// state: { from: location }
// }}
// />
// )
// }
// />
// );
// }
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={(
{ location, ...routeProps } // match.params.token is here
) =>
isLoggedIn || isAccountVerified ? (
<Component {...routeProps} />
) : (
<Redirect
to={{
pathname: '/',
state: { from: location }
}}
/>
)
}
/>
);
}
return (
<>
<Switch>
<Route
path="/"
isLoggedIn={isLoggedIn}
exact
render={props => (
<LinkNavWithLayout {...props} data={navBars}>
<Index />
</LinkNavWithLayout>
)}
/>
<PrivateRoute path="/profile" isLoggedIn={isLoggedIn}>
<LinkNavWithLayout data={navBars}>
<Profile user />
</LinkNavWithLayout>
</PrivateRoute>
<PrivateRoute path="/dashboard" isLoggedIn={isLoggedIn}>
<LinkNavWithLayout data={navBars}>
<Dashboard />
</LinkNavWithLayout>
</PrivateRoute>
<Route path="/login" render={props => <Login {...props} />} />
<Route
path="/forgot_password"
render={props => <ForgotPassword {...props} />}
/>
<Route path="/reset_password" render={props => <ResetPassword {...props} />} />
<PrivateRoute
path="/confirmed/:token"
isAccountVerified={isAccountVerified}
component={Confirmation}
/>
<Route path="/register" render={props => <Register {...props} />} />
<Route
component={({ location }) => (
<h1>
Sorry but the page{' '}
<p style={{ fontWeight: 'strong' }}>{location.pathname.substring(1)} </p>{' '}
Page, Could Not be found
</h1>
)}
/>
</Switch>
</>
);
}
}
function mapStateToProps(state) {
const { ui, users } = state;
const { isLoggedIn, userAvatar, isAccountVerified } = users;
const { modalActive } = ui;
return { isLoggedIn, isAccountVerified, userAvatar, modalActive };
}
const mapDispatchToProps = dispatch =>
bindActionCreators({ modalStateOn, modalStateOff, logInUser, logOutUser }, dispatch);
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(App)
);
确认组件:
import React, { Component } from 'react';
import { Loader, Dimmer, Transition, Message } from 'semantic-ui-react';
import { hasBeenVerified } from '../../store/reducers/users/index';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
class Confirmation extends Component {
constructor(props) {
super(props);
this.state = {
duration: 500,
confirmedParam: false,
responseMessage: {},
error: false
};
}
componentDidMount() {
var { token } = this.props.match.params;
axios
.get(`http://localhost:8016/users/confirmation/${token}`)
.then(response => {
console.log('response', response);
if (response.status === 200) {
hasBeenVerified();
this.setState({
responseMessage: response.data.msg
});
}
this.setState(() => ({ confirmedParam }));
})
.catch(
function(error) {
if (error.response.status === 404) {
this.setState({
responseMessage: error.response.data.msg,
error: true
});
return;
}
if (error.response.status === 400) {
this.setState({
responseMessage: error.response.data.msg,
error: true
});
return;
}
}.bind(this)
);
}
render() {
var { responseMessage } = this.state;
var { isAccountVerified } = this.props;
return (
<div className="login-form">
<Transition
visible={isAccountVerified}
unmountOnHide={true}
animation="scale"
duration={duration}
>
{isAccountVerified ? (
<Dimmer active inverted>
<Loader />
</Dimmer>
) : (
<Message success header={responseMessage[0]} />
)}
</Transition>
</div>
);
}
}
function mapStateToProps(state) {
const { users } = state;
const { isAccountVerified } = users;
return { isAccountVerified };
}
const mapDispatchToProps = dispatch => bindActionCreators({ hasBeenVerified }, dispatch);
export default connect(
mapStateToProps,
mapDispatchToProps
)(Confirmation);
这是应该发生的事情,在注册后他们必须等待我通过 nodemailer
发送的电子邮件,一旦收到它就会有一个 link指向上面的路线,例如http://localhost:8016/confirmed/245dd2b35b634d11d2e10770a994c810
然后该组件对我的 express 应用程序生成 XHR
:
router.route('/confirmation/:token').get((req, res, next) => {
var usersToken = req.params.token;
try {
Token.findOne({ token: usersToken }, function(err, token) {
if (err)
return res.status(404).send({
msg: ['We were unable to find a valid token. Your token my have expired.']
});
// If we found a token, find a matching user
User.findOne({ _id: token._userId, email: req.body.username }, function(err, user) {
if (err)
return res
.status(404)
.send({ msg: ['We were unable to find a user for this token.'] });
if (user.isVerified)
return res.status(400).send({
msg: ['This user has already been verified.']
});
// Verify and save the user
user.isVerified = true;
user.save(function(err) {
if (err) {
return res.status(500).send({ msg: err.message });
}
});
return res
.status(200)
.send({ msg: ['The account has been verified. Please log in.'] });
});
});
} catch (err) {
return next(err);
}
});
并且结果应该更新给用户,即 Confirmation
组件....
传递组件引用并在您的路由中初始化它,而不是在父级别。
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={({ location, ...routeProps }) => // match.params.token is here
isLoggedIn || isAccountVerified ? (
<Component {...routeProps} />
) : (
<Redirect
to={{
pathname: '/',
state: { from: location }
}}
/>
)
}
/>
);
}
<PrivateRoute
path="/confirmed/:token"
isAccountVerified={isAccountVerified}
component={Confirmation}
/>
将 spread operator 添加到 ...children
解决了我的问题!
function PrivateRoute({ children, ...rest }) {
return (
<Route
{...rest}
render={({ location }) =>
isLoggedIn || isAccountVerified ? (
{ ...children } /* spread operator */
) : (
<Redirect
to={{
pathname: '/',
state: { from: location }
}}
/>
)
}
/>
);
}
我做了一个私有路由功能:
function PrivateRoute({ children, ...rest }) {
return (
<Route
{...rest}
render={({ location }) =>
isLoggedIn || isAccountVerified ? (
children
) : (
<Redirect
to={{
pathname: '/',
state: { from: location }
}}
/>
)
}
/>
);
}
现在我想要的是 Route
组件的任何 child 都可以访问其 :params
属性:
<PrivateRoute
path="/confirmed/:token"
isAccountVerified={isAccountVerified}>
<Confirmation />
</PrivateRoute>
这样我就可以在这个组件中使用它了:
class Confirmation extends Component {
constructor(props) {
super(props);
this.state = {
...somestate
};
}
componentDidMount() {
var { token } = this.props.token; // Use it here!!!!
axios
.get(`http://localhost:8016/users/confirmation/${token}`)
.then(response => {
console.log('response', response);
if (response.status === 200) {
this.setState({
responseMessage: response.data.msg
});
}
this.setState(() => ({ confirmedParam }));
})
.catch(
function(error) {
if (error.response.status === 404) {
this.setState({
responseMessage: error.response.data.msg,
error: true
});
return;
}
if (error.response.status === 400) {
this.setState({
responseMessage: error.response.data.msg,
error: true
});
return;
}
}.bind(this)
);
}
render() {
.....
}
如何实现?黑魔法很好...
20 年 3 月 22 日更新
客户端路由:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { logInUser, logOutUser } from '../store/reducers/users/index';
import { bindActionCreators } from 'redux';
import { Switch, Route, Redirect, withRouter } from 'react-router-dom';
import LinkNavWithLayout from './LinkNavWithLayout';
import Index from './home';
import Profile from './profile';
import Dashboard from './dashboard';
import ForgotPassword from './forgotPassword';
import ResetPassword from './resetPassword';
import Login from './login';
import Confirmation from './confirmation';
import { modalStateOn, modalStateOff } from '../store/reducers/ui/index';
import Register from './register';
class App extends Component {
static getInitialProps({
store,
isAccountVerified,
isLoggedIn,
logInUser,
logOutUser
}) {
console.log('store', store);
return { store, isAccountVerified, isLoggedIn, logInUser, logOutUser };
}
constructor(props) {
super(props);
}
render() {
const { isLoggedIn, isAccountVerified } = this.props;
console.log('isAccountVerified ', isAccountVerified);
console.log('this.props ', this.props);
let navBars = [
{ name: 'Home', path: '/' },
{ name: 'Profile', path: '/profile' },
{ name: 'Dashboard', path: '/dashboard' },
{ name: 'Log in', path: '/login' },
{ name: 'Register', path: '/register' }
];
// function PrivateRoute({ children, ...rest }) {
// return (
// <Route
// {...rest}
// render={({ location }) =>
// isLoggedIn || isAccountVerified ? (
// { ...children }
// ) : (
// <Redirect
// to={{
// pathname: '/',
// state: { from: location }
// }}
// />
// )
// }
// />
// );
// }
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={(
{ location, ...routeProps } // match.params.token is here
) =>
isLoggedIn || isAccountVerified ? (
<Component {...routeProps} />
) : (
<Redirect
to={{
pathname: '/',
state: { from: location }
}}
/>
)
}
/>
);
}
return (
<>
<Switch>
<Route
path="/"
isLoggedIn={isLoggedIn}
exact
render={props => (
<LinkNavWithLayout {...props} data={navBars}>
<Index />
</LinkNavWithLayout>
)}
/>
<PrivateRoute path="/profile" isLoggedIn={isLoggedIn}>
<LinkNavWithLayout data={navBars}>
<Profile user />
</LinkNavWithLayout>
</PrivateRoute>
<PrivateRoute path="/dashboard" isLoggedIn={isLoggedIn}>
<LinkNavWithLayout data={navBars}>
<Dashboard />
</LinkNavWithLayout>
</PrivateRoute>
<Route path="/login" render={props => <Login {...props} />} />
<Route
path="/forgot_password"
render={props => <ForgotPassword {...props} />}
/>
<Route path="/reset_password" render={props => <ResetPassword {...props} />} />
<PrivateRoute
path="/confirmed/:token"
isAccountVerified={isAccountVerified}
component={Confirmation}
/>
<Route path="/register" render={props => <Register {...props} />} />
<Route
component={({ location }) => (
<h1>
Sorry but the page{' '}
<p style={{ fontWeight: 'strong' }}>{location.pathname.substring(1)} </p>{' '}
Page, Could Not be found
</h1>
)}
/>
</Switch>
</>
);
}
}
function mapStateToProps(state) {
const { ui, users } = state;
const { isLoggedIn, userAvatar, isAccountVerified } = users;
const { modalActive } = ui;
return { isLoggedIn, isAccountVerified, userAvatar, modalActive };
}
const mapDispatchToProps = dispatch =>
bindActionCreators({ modalStateOn, modalStateOff, logInUser, logOutUser }, dispatch);
export default withRouter(
connect(
mapStateToProps,
mapDispatchToProps
)(App)
);
确认组件:
import React, { Component } from 'react';
import { Loader, Dimmer, Transition, Message } from 'semantic-ui-react';
import { hasBeenVerified } from '../../store/reducers/users/index';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
class Confirmation extends Component {
constructor(props) {
super(props);
this.state = {
duration: 500,
confirmedParam: false,
responseMessage: {},
error: false
};
}
componentDidMount() {
var { token } = this.props.match.params;
axios
.get(`http://localhost:8016/users/confirmation/${token}`)
.then(response => {
console.log('response', response);
if (response.status === 200) {
hasBeenVerified();
this.setState({
responseMessage: response.data.msg
});
}
this.setState(() => ({ confirmedParam }));
})
.catch(
function(error) {
if (error.response.status === 404) {
this.setState({
responseMessage: error.response.data.msg,
error: true
});
return;
}
if (error.response.status === 400) {
this.setState({
responseMessage: error.response.data.msg,
error: true
});
return;
}
}.bind(this)
);
}
render() {
var { responseMessage } = this.state;
var { isAccountVerified } = this.props;
return (
<div className="login-form">
<Transition
visible={isAccountVerified}
unmountOnHide={true}
animation="scale"
duration={duration}
>
{isAccountVerified ? (
<Dimmer active inverted>
<Loader />
</Dimmer>
) : (
<Message success header={responseMessage[0]} />
)}
</Transition>
</div>
);
}
}
function mapStateToProps(state) {
const { users } = state;
const { isAccountVerified } = users;
return { isAccountVerified };
}
const mapDispatchToProps = dispatch => bindActionCreators({ hasBeenVerified }, dispatch);
export default connect(
mapStateToProps,
mapDispatchToProps
)(Confirmation);
这是应该发生的事情,在注册后他们必须等待我通过 nodemailer
发送的电子邮件,一旦收到它就会有一个 link指向上面的路线,例如http://localhost:8016/confirmed/245dd2b35b634d11d2e10770a994c810
然后该组件对我的 express 应用程序生成 XHR
:
router.route('/confirmation/:token').get((req, res, next) => {
var usersToken = req.params.token;
try {
Token.findOne({ token: usersToken }, function(err, token) {
if (err)
return res.status(404).send({
msg: ['We were unable to find a valid token. Your token my have expired.']
});
// If we found a token, find a matching user
User.findOne({ _id: token._userId, email: req.body.username }, function(err, user) {
if (err)
return res
.status(404)
.send({ msg: ['We were unable to find a user for this token.'] });
if (user.isVerified)
return res.status(400).send({
msg: ['This user has already been verified.']
});
// Verify and save the user
user.isVerified = true;
user.save(function(err) {
if (err) {
return res.status(500).send({ msg: err.message });
}
});
return res
.status(200)
.send({ msg: ['The account has been verified. Please log in.'] });
});
});
} catch (err) {
return next(err);
}
});
并且结果应该更新给用户,即 Confirmation
组件....
传递组件引用并在您的路由中初始化它,而不是在父级别。
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={({ location, ...routeProps }) => // match.params.token is here
isLoggedIn || isAccountVerified ? (
<Component {...routeProps} />
) : (
<Redirect
to={{
pathname: '/',
state: { from: location }
}}
/>
)
}
/>
);
}
<PrivateRoute
path="/confirmed/:token"
isAccountVerified={isAccountVerified}
component={Confirmation}
/>
将 spread operator 添加到 ...children
解决了我的问题!
function PrivateRoute({ children, ...rest }) {
return (
<Route
{...rest}
render={({ location }) =>
isLoggedIn || isAccountVerified ? (
{ ...children } /* spread operator */
) : (
<Redirect
to={{
pathname: '/',
state: { from: location }
}}
/>
)
}
/>
);
}