import React from "react"; import { isValidElementType } from "react-is"; import PropTypes from "prop-types"; import invariant from "tiny-invariant"; import warning from "tiny-warning"; import RouterContext from "./RouterContext.js"; import matchPath from "./matchPath.js"; function isEmptyChildren(children) { return React.Children.count(children) === 0; } function evalChildrenDev(children, props, path) { const value = children(props); warning( value !== undefined, "You returned `undefined` from the `children` function of " + `, but you ` + "should have returned a React element or `null`" ); return value || null; } /** * The public API for matching a single path and rendering. */ class Route extends React.Component { render() { return ( {context => { invariant(context, "You should not use outside a "); const location = this.props.location || context.location; const match = this.props.computedMatch ? this.props.computedMatch // already computed the match for us : this.props.path ? matchPath(location.pathname, this.props) : context.match; const props = { ...context, location, match }; let { children, component, render } = this.props; // Preact uses an empty array as children by // default, so use null if that's the case. if (Array.isArray(children) && isEmptyChildren(children)) { children = null; } return ( {props.match ? children ? typeof children === "function" ? __DEV__ ? evalChildrenDev(children, props, this.props.path) : children(props) : children : component ? React.createElement(component, props) : render ? render(props) : null : typeof children === "function" ? __DEV__ ? evalChildrenDev(children, props, this.props.path) : children(props) : null} ); }} ); } } if (__DEV__) { Route.propTypes = { children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]), component: (props, propName) => { if (props[propName] && !isValidElementType(props[propName])) { return new Error( `Invalid prop 'component' supplied to 'Route': the prop is not a valid React component` ); } }, exact: PropTypes.bool, location: PropTypes.object, path: PropTypes.oneOfType([ PropTypes.string, PropTypes.arrayOf(PropTypes.string) ]), render: PropTypes.func, sensitive: PropTypes.bool, strict: PropTypes.bool }; Route.prototype.componentDidMount = function() { warning( !( this.props.children && !isEmptyChildren(this.props.children) && this.props.component ), "You should not use and in the same route; will be ignored" ); warning( !( this.props.children && !isEmptyChildren(this.props.children) && this.props.render ), "You should not use and in the same route; will be ignored" ); warning( !(this.props.component && this.props.render), "You should not use and in the same route; will be ignored" ); }; Route.prototype.componentDidUpdate = function(prevProps) { warning( !(this.props.location && !prevProps.location), ' elements should not change from uncontrolled to controlled (or vice versa). You initially used no "location" prop and then provided one on a subsequent render.' ); warning( !(!this.props.location && prevProps.location), ' elements should not change from controlled to uncontrolled (or vice versa). You provided a "location" prop initially but omitted it on a subsequent render.' ); }; } export default Route;