我想使用react-router生命周期来设置过渡-在用户尝试通过未保存的更改离开表单时通知用户。
我对使用此功能特别感兴趣:
routerWillLeave(nextLocation) {
if(!this.state.isSaved)
return 'Your work is not saved! Are you sure you want to leave?'
}
我尝试使用'react-mixin'语法:
reactMixin.onClass(ManageCoursePage, Lifecycle);
我得到这个错误:
Invariant Violation: The Lifecycle mixin must be used on either a) a <Route component> or b) a descendant of a <Route component> that uses the RouteContext mixin
似乎我缺少有关RouteComponents和RouteContext的东西?非常感谢任何见解...
我的代码:
ManageCoursePage.js
import React, {PropTypes} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import reactMixin from 'react-mixin';
import { Lifecycle } from 'react-router';
import {authorsFormattedForDropdown} from '../../selectors/selectors';
import * as courseActions from '../../actions/courseActions';
import * as authorActions from '../../actions/authorActions';
import CourseForm from './CourseForm';
export class ManageCoursePage extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
course: Object.assign({}, this.props.course),
errors: {},
saving: false
};
this.routerWillLeave = this.routerWillLeave.bind(this);
this.updateCourseState = this.updateCourseState.bind(this);
this.saveCourse = this.saveCourse.bind(this);
}
routerWillLeave(nextLocation) {
if(!this.state.isSaved)
return 'Your work is not saved! Are you sure you want to leave?'
}
componentWillReceiveProps(nextProps) {
if (this.props.course.id != nextProps.course.id) {
//Necessary to populate form when existing course is loaded directly
this.setState({course: Object.assign({}, nextProps.course)});
}
}
updateCourseState(event) {
const field = event.target.name;
let course = this.state.course;
course[field] = event.target.value;
console.log("change");
return this.setState({course: course});
}
courseFormIsValid() {
let formIsValid = true;
let errors = {};
if(this.state.course.title.length < 5) {
errors.title = 'Title must be at least 5 characters.';
formIsValid = false;
}
this.setState({errors: errors});
return formIsValid;
}
saveCourse(event){
event.preventDefault();
if (!this.courseFormIsValid()) {
return;
}
this.setState({saving: true});
this.props.actions.saveCourse(this.state.course)
.then(() => this.redirect())
.catch(error => {
toastr.error(error);
this.setState({saving: false});
});
}
redirect() {
this.setState({saving: false});
toastr.success('Course saved');
this.context.router.push('/courses');
}
render() {
return (
<CourseForm
allAuthors={this.props.authors}
onChange={this.updateCourseState}
onSave={this.saveCourse}
course={this.state.course}
errors={this.state.errors}
saving={this.state.saving}
/>
);
}
}
reactMixin.onClass(ManageCoursePage, Lifecycle);
ManageCoursePage.propTypes = {
course: PropTypes.object.isRequired,
authors: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
};
ManageCoursePage.contextTypes = {
router: PropTypes.object
};
function getCourseById(courses, id){
const course = courses.filter(course => course.id == id);
if (course) return course[0]; //filter returns an array, so you have to grab the first value.
return null;
}
function mapStateToProps(state, ownProps) {
const courseId = ownProps.params.id; // from the path '/course/:id'
let course = {id: '', watchHref: '', title: '', authorId: '', length: '', category: ''};
if (courseId && state.courses.length > 0) {
course = getCourseById(state.courses, courseId);
}
return {
course: course,
authors: authorsFormattedForDropdown(state.authors)
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(courseActions, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(ManageCoursePage);
routes.js
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from './components/App';
import HomePage from './components/home/HomePage';
import AboutPage from './components/about/AboutPage';
import CoursesPage from './components/course/CoursesPage';
import AuthorsPage from './components/author/AuthorsPage';
import ManageAuthorPage from './components/author/ManageAuthorPage';
import ManageCoursePage from './components/course/ManageCoursePage'; //eslint-disable-line import/no-named-as-default
export default (
<Route path="/" component={App}>
<IndexRoute component={HomePage} />
<Route path="about" component={AboutPage} />
<Route path="courses" component={CoursesPage} />
<Route path="course" component={ManageCoursePage} />
<Route path="course/:id" component={ManageCoursePage} />
<Route path="authors" component={AuthorsPage} />
<Route path="author" component={ManageAuthorPage} />
<Route path="author/:id" component={ManageAuthorPage} />
</Route>
);
最佳答案
我能够使用this.context.route.setRouteLeaveHook
在我的ES6类中设置路由离开挂钩。
问题解决了。