Im using react: 17.0.2 and react-router-dom: 6.3.0.
My current App.js snippet looks like this:
class App extends React.Component {
render() {
return (
<div className="App">
<Routes>
<Route element={<Layout/>}>
<Route path="/home" element={<Home/>} />
<Route path="/login" element={<Login/>} />
<Route path="/signup" element={<Signup/>} />
</Route>
<Route exact path='/' element={<Intro/>}/>
</Routes>
</div>
);
}
}
The route to '/' should not use the Layout component, so I need to exclude it from the context.
Within Layout.js I need to access the children like so:
const Layout = ({ children }) => {
console.log(children)
return (
<div>
<main>{children}</main>
</div>
);
};
But children are undefined in the above example. I can access children in Layout.js when I rewrite App.js to the below snippet, but then '/' is also rendered with the Layout.
class App extends React.Component {
render() {
return (
<div className="App">
<Layout>
<Routes>
<Route path="/home" element={<Home/>} />
<Route path="/login" element={<Login/>} />
<Route path="/signup" element={<Signup/>} />
<Route exact path='/' element={<Intro/>}/>
</Routes>
</Layout>
</div>
);
}
}
export default App;
How can I access children in Layout.js and render path '/' without the layout.
Route and Routes work a little differently in v6. The Route and React.Fragment components are the only valid children of the Routes component, and other Route components the only valid children of the Route. Layout routes must render an Outlet component for the nested routes to render their contents into.
import { Outlet } from 'react-router-dom';
const Layout = () => {
return (
<div>
<main>
<Outlet />
</main>
</div>
);
};
I'm not sure if I'm using a HOC correctly but I have state at the top app level which needs to be updated from a child components that exists in a HOC.
my main app router that holds the state
class AppRouter extends React.Component {
state = {
selected: "",
};
updateSelected = selected => {
this.setState({ selected });
};
updateReports = reports => {
this.setState({ reports });
};
render() {
return (
<Router history={history}>
<div>
<div className="holygrail">
<Header setIsAuth={this.setIsAuth} isAuth={this.state.isAuth} />
<Switch>
<PublicRoute
path="/login"
isAuth={this.state.isAuth}
component={() => <Login setIsAuth={this.setIsAuth} />}
exact={true}
/>
<PrivateRoute
path="/"
selected={this.state.selected}
isAuth={this.state.isAuth}
updateSelected={this.updateSelected}
updateReports={this.updateReports}
component={Dashboard}
exact={true}
/>
<Route component={NotFound} />
</Switch>
</div>
</div>
</Router>
);
}
}
export default AppRouter;
I have a PrivateRoute that then has a template which include a nav that should not be shown on a PublicRoute
export const PrivateRoute = ({ component: Component, isAuth, ...rest }) => (
<Route
{...rest}
render={props => {
console.log("Private Route ", isAuth);
return isAuth ? (
<div className="holygrail-body">
<Nav
updateSelected={this.updateSelected} <-- how to pass these back up to AppRouter parent?
updateReports={this.updateReports}
/>
<Component {...props} />
</div>
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
);
}}
/>
);
export default PrivateRoute;
How do I pass the Nav props to update the main component state.
I'm setting up a student social network application. I am using react, redux and react router. My feed list component keep the student id from url. When i use from react router, my component do not update.
I read this article https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md and tried to wrap my components in withRouter.
index.js :
ReactDOM.render(
<Provider store={store}>
<Router>
<Route path="/" component={App} />
<Route exact path="/sign/In" component={SignIn} />
<Route exact path="/sign/Up" component={SignUp} />
</Router>
</Provider>, document.getElementById('root'));
App.js :
class App extends Component {
render() {
return (
<Router id="Page" >
<div className={this.props.AppStore.Theme}>
<header>
<NavBar />
</header>
<Route exact path="/" component={HomePage} />
<Route exact path="/#:id" component={feedpage} />
</div>
</Router>
);
}
}
const mapStateToProps = (state) => {
return state
}
export default withRouter(connect(mapStateToProps)(App));
feedPage.js :
class feedPage extends Component {
componentDidMount() {
const {dispatch} = this.props;
API.requireFeed(this.props.match.params.id,"profil",20)
.then((res) => {
if(res){
dispatch(postList(res));
}
})
}
render() {
return (
<div id="Page">
<div id="mainPage">
<div id="centralCard">
{this.props.postList.map((element) => (
<div>
<Link to={'/#'+element.Pseudo}>{element.Pseudo}</Link>
<p>{element.Content}</p>
</div>
))}
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return state
}
export default withRouter(connect(mapStateToProps)(feedPage));
I expect to have update of the component each Time i click on a link to an other feedPage.
I someone have an idea about how to resolve the issue, i would be enjoing it :)
You should have just one router component (that in index.js), nested routing in your app component does not require another router, just declare your routes.
I don't understand why component Sample is not rendering at all. Url changes, no errors in console, however component is not mounted. No matter if it is functional component or React class. And why inline component with URL "/thisworks" is rendered properly. What am I doing wrong here?
index.jsx:
render(
<Provider store={store}>
<Root />
</Provider>,
document.getElementById("root")
);
root.js:
const Root = () => (
<div>
<BrowserRouter>
<Switch>
// routes below work fine
<Route path="/login" component={LoginPage} />
<Route path="/" component={App} />
</Switch>
</BrowserRouter>
<DevTools />
</div>
)
App.js:
class App extends React.Component {
render() {
return (
<div>
<NavMenu />
<Switch>
<Route path="/thisworks" render={(props) => {
return (<div>This works!</div>);
}} />
<Route path="/sample" Component={Sample} /> // not working - not rendering component Sample
<Redirect from="/" to="/sample" />
</Switch>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => ({})
const mapDispatchToProps = (dispatch) => ({})
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App))
Sample.jsx:
const Sample = (props) => {
return (
<div>
Sample!
</div>
);
}
export default Sample;
Maybe component instead of Component?
<Route path="/sample" component={Sample} />
New to react & react-router.
I'm trying to understand this example:
https://github.com/ReactTraining/react-router/blob/1.0.x/docs/API.md#components-1
But this.props never contains main or sidebar. My code:
Main.js
ReactDOM.render(
<Router>
<Route path="/" component={App2}>
<Route path="/" components={{main: Home, sidebar: HomeSidebar}}/>
</Route>
</Router>,
document.getElementById('content')
);
App2.js
class App2 extends React.Component {
render() {
const {main, sidebar} = this.props;
return (
<div>
<Menu inverted vertical fixed="left">
{sidebar}
</Menu>
<Container className="main-container">
{main}
</Container>
</div>
);
}
}
export default App2;
Home.js
import React from 'react';
class Home extends React.Component {
render() {
return (
<div><h1>Home</h1></div>
);
}
}
export default Home;
HomeSidebar.js
class HomeSidebar extends React.Component {
render() {
return (
<div>
<p>I'm a sidebar</p>
</div>
);
}
}
export default HomeSidebar;
I'm using electron with react dev tools. Whenever I debug, this.props contains neither main nor sidebar. Any idea why this is happening?
I've also tried using an IndexRoute, but it seems to not support a components prop.
Other things I've tried
ReactDOM.render(
<Router>
<Route component={App2}>
<Route path="/" components={{main: Home, sidebar: HomeSidebar}}/>
</Route>
</Router>,
document.getElementById('content')
);
ReactDOM.render(
<Router>
<Route path="/" component={App2} components={{main: Home, sidebar: HomeSidebar}}>
<Route path="admin" components={{main: Admin, sidebar: AdminSidebar}}/>
</Route>
</Router>,
document.getElementById('content')
);
Looks like to have the components prop work you need use the <IndexRoute /> component instead of <Route />. In the react-router docs it mentions that IndexRoute has all of the same props as Route so doing
<IndexRoute components={{main: Main, side: Side}} />
works!
Full code:
React.render((
<Router>
<Route path="/" component={App} >
<IndexRoute components={{main: Main, side: Side}} />
</Route>
</Router>
), document.getElementById('app'))
Codepen: http://codepen.io/chmaltsp/pen/ZeLaPr?editors=001
Cheers!
If you're using the current version of react-router (v4.0.0), it looks like they did away with the components prop on Routes: https://reacttraining.com/react-router/web/api/Route
You can render Routes anywhere, and they even have a sidebar example where they do just that. They have one set of Route components to render the main components and another set of Route components for sidebars, but both come from a single route config to keep it DRY.
To translate that to your code, you could create a route config:
const routes = [
{ path: '/',
sidebar: Sidebar
main: Main
}
];
Then in Main.js
ReactDOM.render(
<Router>
<Route component={App2}>
{routes.map((route, index) => (
<Route
key={index}
path={route.path}
component={route.main}
/>
))}
</Route>
</Router>,
document.getElementById('content')
);
Then in App2.js
class App2 extends React.Component {
render() {
return (
<div>
<Menu inverted vertical fixed="left">
{routes.map((route, index) => (
<Route
key={index}
path={route.path}
component={route.sidebar}
/>
))}
</Menu>
<Container className="main-container">
{this.props.children}
</Container>
</div>
);
}
}
export default App2;
The example from github was written 2 years ago (look here) and I'am not sure for which particular version it is related. And I'am not sure does it works now (because I am also new with react), but I know that you don't have use this approach to reach this aim, you can use separated component which will contains mainz and sidebar, here my example:
class App2 extends React.Component {
render() {
return (
// Your Menu.
// Your Container.
<div>
{this.props.children}
</div>
);
}
}
class Home extends React.Component {
render() {
return (<div><h1>Home</h1></div>);
}
}
class HomeSidebar extends React.Component {
render() {
return (<div><p>I am a sidebar</p></div>);
}
}
class HomeWithSidebar extends React.Component {
render() {
return (
<div>
<Home />
<HomeSidebar />
</div>
);
}
}
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={App2}>
<Route path="/a2" components={HomeWithSidebar} />
</Route>
</Router>,
document.getElementById('content')
);
PS: Don't forget use <Router history={browserHistory}> in your example.
And use IndexRoute in your example or specify another, like /a2 in my example.
Im new to react router myself but I am sure that the routes you are using are incorrect. in the example you give you have 2 different routes that resolve to the same path (/):
ReactDOM.render(
<Router>
<Route path="/" component={App2}>
<Route path="/" components={{main: Home, sidebar: HomeSidebar}}/>
</Route>
</Router>,
document.getElementById('content')
);
I beleieve this should be something like:
ReactDOM.render(
<Router>
<Route path="/" component={App2}>
<IndexRoute components={{main: Home, sidebar: HomeSidebar}}/>
<Route path="some/other/path" components={{main: Home, sidebar: SomeOtherSidebar}}/>
</Route>
</Router>,
document.getElementById('content')
);
I hope you know that you are using react-router 1.0.x and it is quite outdated. Current version is 4.x.
Below code works perfectly( based on your example provided).
let Router = ReactRouter.Router;
let RouterContext = Router.RouterContext;
let Route = ReactRouter.Route;
class App2 extends React.Component {
render () {
const { main, sidebar } = this.props;
return (
<div>
<div className="Main">
{main}
</div>
<div className="Sidebar">
{sidebar}
</div>
</div>
)
}
}
class Home extends React.Component {
render() {
return (
<div><h1>Home</h1></div>
);
}
}
class HomeSidebar extends React.Component {
render() {
return (
<div>
<p>I'm a sidebar</p>
</div>
);
}
}
ReactDOM.render(
<Router>
<Route component={App2}>
<Route path="/" components={{main: Home, sidebar: HomeSidebar}}/>
</Route>
</Router>,
document.getElementById('content')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router/1.0.3/ReactRouter.min.js"></script>
<div id="content"></div>