Liondancer Liondancer - 3 months ago 19
React JSX Question

How does React context know I am referencing react-router to redirect me to another URL

For my component, I set a context

ManageCoursePage.contextTypes = {
router: PropTypes.object
};


How does my class method know that I am referencing react router to automatically redirect me to another URL?

this.context.router.push('/courses');


Here is my component code:

import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as courseActions from '../../actions/courseActions';
import CourseForm from './courseForm';


class ManageCoursePage extends React.Component {
constructor(props, context) {
super(props, context);

// set up local state
this.state = {
errors: {},
course: Object.assign({}, this.props.course)
};

this.updateCourseState = this.updateCourseState.bind(this);
this.saveCourse = this.saveCourse.bind(this);

}

updateCourseState(event) {
const field = event.target.name;
let course = this.state.course;
course[field] = event.target.value;
return this.setState({
course: course
});
}

saveCourse(event) {
event.preventDefault();
this.props.actions.saveCourse(this.state.course);
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 }

/>
);
}
}

ManageCoursePage.propTypes = {
// myProp: PropTypes.string.isRequired
course: PropTypes.object.isRequired,
authors: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
};

// Pull in the React Router context so router is available on this.context.router
// basically a global variable to make it easy for other components to get data easily
ManageCoursePage.contextTypes = {
router: PropTypes.object
};

function mapStateToProps(state, ownProps) {
// empty course
let course = {
id: "",
watchHref: "",
title: "",
authorId: "",
length: "",
category: ""
};

const authorsFormattedForDropDown = state.authors.map(author => {
return {
value: author.id,
text: author.firstName + " " + author.lastName
};
});

return {
course: course,
authors: authorsFormattedForDropDown
};
}

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(courseActions, dispatch)
};
}

export default connect(mapStateToProps, mapDispatchToProps)(ManageCoursePage);

Answer

Very interesting question. :)

It works because router is defined as a childContext type in the react-router library. getChildContext will make this accessible in inside the application if you map contextTypes in a component.

This is helpful in many ways to avoid deeply passing the props from a parent component to deep child component.

Refer this in react-router library https://github.com/reactjs/react-router/blob/master/modules/RouterContext.js#L36

And also the documentation https://facebook.github.io/react/docs/context.html