Поскольку вы переходите на интерфейсную маршрутизацию, я бы рекомендовал интегрировать react-router
(я предпочитаю v3.0.4, а не v4.x) для обработки только интерфейсной маршрутизации и express
(или что выиспользование) для обработки только внутренних запросов API.
Следующий пример предназначен только для демонстрации маршрутизации и не должен использоваться как есть.
Сначала настройте прокси в клиентской package.json
(Основное преимущество этого состоит в том, чтобы избежать использования CORS
):
"proxy": {
"/api/*": {
"target": "http://localhost:8080"
}
}
Мой клиент routes
будет настроен таким образом, чтобы App
всегда оставался подключенным и действовал как сквозной для маршрутов children
:
client / src / router / index.js
import React from 'react';
import { Route } from 'react-router';
import App from '../components/App';
import Dashboard from '../components/Dashboard';
import NotFound from '../components/NotFound';
export default (
<Route path="/" component={App}>
<Route path="dashboard" component={Dashboard} />
<Route path="*" component={NotFound} />
</Route>
);
В моем App.js
я мог бы использовать проверку состояния isAuthenticated
:
client / src / components / App.js
import React, { Component, Fragment } from 'react';
import { browserHistory } from 'react-router';
import LoginForm from './LoginForm'
export default class App extends Component {
state = { isAuthenticated: false };
componentDidMount = () => !this.state.isAuthenticated && browserHistory.push('/')
componentDidUpdate = (prevProps, prevState) => !this.state.isAuthenticated && browserHistory.push('/')
authenticated = () => this.setState({ isAuthenticated: true }, () => browserHistory.push('/dashboard'))
render = () => (
!this.state.isAuthenticated
? <LoginForm authenticated={this.authenticated} />
: <Fragment>
{this.props.children}
</Fragment>
)
}
Затем в компоненте LoginForm
я мог бы установить isAuthenticated
в true через this.props.authenticated
послеуспешный AJAX
запрос, а затем перенаправить на dashboard
:
client / src / components / LoginForm.js
import React, {Component} from 'react';
import axios from 'axios';
export default class LoginForm extends Component {
state = {
login: "",
password: ""
}
handleChange = e => this.setState({ [e.target.name]: e.target.value })
handleSubmit = e => {
e.preventDefault();
const { login, password } = this.state;
if (!login || !password ) return;
axios.post('/api/login', { login, password })
.then(() => this.props.authenticated())
.catch(err => console.error(err.toString()))
}
render = () => (
<form onSubmit={this.handleSubmit} className="some-class">
<input
name="login"
type="text"
value={this.state.login}
placeholder="Username"
onChange={this.handleChange}
/>
<input
name="password"
type="password"
value={this.state.password}
placeholder="Password"
onChange={this.handleChange}
/>
<button type="submit" className="some-class">
Log In
</button>
</form>
)
}
Затем экспресс-сервер routes
будет искать POST
запрос:
сервер / маршруты / auth.js
const { login } = require('../controllers/auth.js');
app.post('/login', login);
Затем я могу аутентифицировать пользователя через passport
вмой экспресс-контроллер (если пользователь не может авторизоваться)d, тогда он будет пойман в AJAX .catch()
внутри handleSubmit
):
server / controllers / auth.js
exports.login = (req, res, done) => passport.authenticate('local-login', (err, user) => {
if (err || !user) { res.status(404).json({ err: "Authentication failed." }); done(); }
res.status(201).send(null);
})(req, res, done)