I'm trying to develop a slide-out menu with routing function for React. for some reason state = {} isn't setting defining sideDrawOpen what could the reasons for this be thanks for your help. the error I get running yarn start is
"Failed to compile.
./src/App.js
Line 21:45: 'sideDrawerOpen' is not defined no-undef
Search for the keywords to learn more about each error."
import React, { Component } from 'react';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import main_page from './components/main_page';
import setup_page from './components/setup_page';
import settings_page from './components/settings_page';
import Error from './components/Error';
import Nav from './components/Navigation/Nav';
import SideDrawer from './components/Navigation/SideDrawer';
import Backdrop from './components/Navigation/Backdrop';
export class App extends Component {
state = {
sideDrawerOpen: false
}
drawerToggleClickHandler = () => {
this.setState((prevState) =>{
return {sideDrawerOpen: !prevState,sideDrawerOpen};
});
};
render() {
let sideDrawer;
let backdrop;
if (this.state.sideDrawerOpen) {
sideDrawer = <SideDrawer />
backdrop = <Backdrop />
}
return (
<div className="App_margin">
<Router>
<div className='App'>
{sideDrawer}
{backdrop}
<Nav />
<Switch>
<Route path='/' component={setup_page} exact/>
<Route path='/main_page' component={main_page} />
<Route path='/settings_page' component={settings_page} />
<Route component={Error} />
</Switch>
</div>
</Router>
</div>
);
}
}
!prevState,sideDrawerOpen has a comma, not a .
Related
I am making a react music player (ok, spotify clone). I don't know about redux and any global states So Iam learning context to change states from another components.
Edit: I am using a codesandbox example = https://codesandbox.io/s/react-context-forked-6t8g7l?file=/src/LanguageSwitcher.js
As usual, I am getting error
This is my App.js =>
import React, { useState, useEffect } from 'react';
import { BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
import IsPlayingContext from './context/IsPlayingContext';
import styles from './style/App.module.css';
function App() {
const [isPlaying,setIsplaying]=useState(false)
const value = { isPlaying,setIsplaying };
return (
<Router >
<div className={styles.layout}>
<IsPlayingContext.Provider value={value} >
{size.width > CONST.MOBILE_SIZE
? <Sidebar />
: <MobileNavigation />
}
<Switch >
<Route exact path="/">
<Home />
</Route>
<Route path="/search">
<Search />
</Route>
<Route path="/library">
<Library />
</Route>
<Route exact path="/playlist/:path">
<PlaylistPage />
</Route>
</Switch>
<Footer />
</IsPlayingContext.Provider>
</div>
</Router>
);
}
export default App;
Footer.js
import React, { useRef, useEffect, useState } from 'react';
import { useContext } from 'react';
import IsPlayingContext from '../../context/IsPlayingContext';
function Footer(props){
const {isPlaying,setIsPlaying} = useContext(IsPlayingContext)
useEffect(() => {
setIsPlaying(true)
// That's the line
}, [])
return (
// Here my usual code
);
}
export default Footer
The error i am getting is =>
Uncaught TypeError: setIsPlaying is not a function
at footer.js:49:1
Please help me I will be very grateful to you
There's a typo mistake, you declared setIsplaying using a small p i in App.js
const [isPlaying,setIsplaying]=useState(false)
const value = { isPlaying,setIsplaying };
and you are accessing it as setIsPlaying where P is a capital letter in the Footer component
const {isPlaying,setIsPlaying} = useContext(IsPlayingContext)
So change it too,
const {isPlaying,setIsplaying} = useContext(IsPlayingContext)
I have a router set up in my App.js as follows:
import React from 'react';
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
import NavBar from './nav-bar';
import Landing from './landing-page';
import Dashboard from './dashboard';
import Analysis from './analysis';
import '../style.scss';
const App = (props) => {
return (
<Router>
<NavBar />
<Switch>
<Route exact path="/" component={Landing} />
<Route path="/dashboard/:prodID/search" component={Dashboard} />
<Redirect from="/dashboard/:prodID" to="/dashboard/:prodID/search" />
<Route path="/dashboard/:prodID/analyze" component={Analysis} />
<Route component={() => (
<div id="error">
<h1>404 ERROR</h1>
<h2>Page not found</h2>
</div>
)}
/>
</Switch>
</Router>
);
};
export default App;
and my NavBar component is set up as follows:
import React, { Component } from 'react';
import { NavLink, withRouter } from 'react-router-dom';
import { Navbar, Nav } from 'react-bootstrap';
import '../style.scss';
class NavBar extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<Navbar id="nav-bar" bg="dark" variant="dark">
<Navbar.Brand href="/">
My Project
</Navbar.Brand>
<Navbar.Collapse id="responsive-navbar-nav" className="justify-content-end">
<Nav>
<NavLink to="/dashboard/:prodID/search">Search</NavLink>
<NavLink to="/dashboard/:prodID/analyze">Analyze</NavLink>
</Nav>
</Navbar.Collapse>
</Navbar>
);
}
}
export default withRouter(NavBar);
I have two things that I'm trying to figure out:
I want to be able to access the prodID route param within my NavBar component so that when a user clicks on the route, it will take the valid prodID and render the route correctly.
I want to only display the NavLinks in NavBar if the user is on a route that has the prodID param. If they're on the home route / for example, the links wouldn't show up. But if they're on the route /dashboard/[valid prodID]/search, the links would show up.
How do I go about implementing this? I've looked at other posts on SO dealing with route params and nav bars, but none of them have answered my question. Any help is appreciated.
I believe you would have to move your navbar under each of the routes, so that it can be re-rendered and grab the correct params when the path changes.
In order to achieve it, you can create the Layout component which will wrap the component you pass and add a navbar to it:
// Layout.jsx
import React from "react";
import NavBar from './nav-bar';
export const Layout = () => {
return (
<div>
<Navbar />
<div>{children}</div>
</div>
);
};
Then in your App, you can wrap each component within the routes with the Layout component like so
// App.jsx
import React from "react";
import {
BrowserRouter as Router,
Route,
Switch,
Redirect
} from "react-router-dom";
import NavBar from "./nav-bar";
import Landing from "./landing-page";
import Dashboard from "./dashboard";
import Analysis from "./analysis";
import { Layout } from "./Layout";
import "../style.scss";
const App = props => {
return (
<Router>
<Switch>
<Route exact path="/">
<Layout>
<Landing />
</Layout>
</Route>
<Route path="/dashboard/:prodID/search">
<Layout>
<Dashboard />
</Layout>
</Route>
<Redirect from="/dashboard/:prodID" to="/dashboard/:prodID/search" />
<Route path="/dashboard/:prodID/analyze">
<Layout>
<Analysis />
</Layout>
</Route>
<Route
component={() => (
<div id="error">
<h1>404 ERROR</h1>
<h2>Page not found</h2>
</div>
)}
/>
</Switch>
</Router>
);
};
export default App;
This approach would help you achieve your second goal. Since the navbar is now nested under each route, you can easily fetch the params from the path and conditionally render the links, like so:
// NavBar.jsx
import React from "react";
import { NavLink, useParams } from "react-router-dom";
import { Navbar, Nav } from "react-bootstrap";
import "../style.scss";
const NavBar = () => {
const { prodID } = useParams();
return (
<Navbar id="nav-bar" bg="dark" variant="dark">
<Navbar.Brand href="/">My Project</Navbar.Brand>
<Navbar.Collapse
id="responsive-navbar-nav"
className="justify-content-end"
>
<Nav>
{prodID && (
<NavLink to={`/dashboard/:${prodID}/search`}>Search</NavLink>
)}
{prodID && (
<NavLink to={`/dashboard/:${prodID}/analyze`}>Analyze</NavLink>
)}
</Nav>
</Navbar.Collapse>
</Navbar>
);
};
export default NavBar;
I haven't tested it, but it should help you with your issues.
So the problem is that I'm new to REACT, I used create-react-app and added a Router function to route between components. Now I created a header which everything was okay with, but I added a hamburger-menu so I could route between my pages and suddenly my Header just got itself duplicated on my webpage.
App.js:
import React, {Component} from 'react';
import { BrowserRouter as Router, Route} from "react-router-dom";
import './App.css';
import './Header.css'
import SideDrawer from "./SideDrawer";
import Header from './Header'
import Backdrop from './Backdrop'
import Home from "./Home";
import LoginPage from "./LoginPage";
import SignupPage from "./SignupPage";
import RegisterEventPage from "./RegisterEventPage";
class App extends Component {
state = {
sideDrawerOpen: false
};
drawerToggleClickHandler = () => {
this.setState((prevState) => {
return {sideDrawerOpen: !prevState.sideDrawerOpen};
});
};
backDropClickHandler = () => {
this.setState({sideDrawerOpen: false});
};
render() {
let sideDrawer;
let backdrop;
if (this.state.sideDrawerOpen) {
sideDrawer = <SideDrawer/>;
backdrop = <Backdrop click={this.backDropClickHandler}/>;
}
return (
<div style={{height: '100%'}}>
<Header drawerClickHandler={this.drawerToggleClickHandler}/>
{sideDrawer}
{backdrop}
<Router>
<Route exact path="/" component={Home}/>
<Route path="/loginPage" component={LoginPage}/>
<Route path="/SignupPage" component={SignupPage}/>
<Route path="/RegisterEventPage" component={RegisterEventPage}/>
</Router>
</div>
);
}
}
export default App;
Header.jsx:
import React, {Component} from 'react';
import DrawerToggleButton from './DrawerToggleButton';
import './Header.css';
class Header extends Component {
render() {
return (
<header className="main_toolbar">
<nav className="toolbar_navigation">
<div>
<DrawerToggleButton click={this.props.drawerClickHandler}/>
</div>
<div className="toolbar_logo">IceBreaker</div>
<div className="spacer"></div>
</nav>
</header>
);
}
}
export default Header;
So if I for example remove from App.js my second header suddenly disappears.
Image of two headers
Render your header inside the router:
I also recomend you to use a switch in your router
You will need to import it :
import { BrowserRouter as Router, Route} from "react-router-dom";
return (
<div style={{height: '100%'}}>
<Router>
<Header drawerClickHandler={this.drawerToggleClickHandler}/>
{sideDrawer}
{backdrop}
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/loginPage" component={LoginPage}/>
<Route path="/SignupPage" component={SignupPage}/>
<Route path="/RegisterEventPage" component={RegisterEventPage}/>
</Switch>
</Router>
</div>
);
I'm just doing some basic routing in my react app and I've done it this way before so I'm pretty confused to as why it isn't working now.
The error I am getting says: You should not use <Route> or withRouter() outside a <Router>
I'm sure this is super basic so thanks for baring with me!
import React from 'react'
import { Route } from 'react-router-dom'
import { Link } from 'react-router-dom'
import * as BooksAPI from './BooksAPI'
import BookList from './BookList'
import './App.css'
class BooksApp extends React.Component {
state = {
books: []
}
componentDidMount() {
this.getBooks()
}
getBooks = () => {
BooksAPI.getAll().then(data => {
this.setState({
books: data
})
})
}
render() {
return (
<div className="App">
<Route exact path="/" render={() => (
<BookList
books={this.state.books}
/>
)}/>
</div>
)
}
}
export default BooksApp
You need to setup context provider for react-router
import { BrowserRouter, Route, Link } from 'react-router-dom';
// ....
render() {
return (
<BrowserRouter>
<div className="App">
<Route exact path="/" render={() => (
<BookList
books={this.state.books}
/>
)}/>
</div>
</BrowserRouter>
)
}
Side note - BrowserRouter should be placed at the top level of your application and have only a single child.
I was facing the exact same issue. Turns out that i didn't wrap the App inside BrowserRouter before using the Route in App.js.
Here is how i fixed in index.js.
import {BrowserRouter} from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
document.getElementById('root')
);
So I've been struggling with this code. I have a component which accepts a child as a prop, and it is supposed to be the base of all the pages I host.
Base.jsx :
import React from 'react';
import PropTypes from 'prop-types';
import { Link, NavLink } from 'react-router-dom';
const Base = ({ child }) => (
<div>
<div className="top-bar">
<div className="top-bar-left">
<NavLink to="/">React App</NavLink>
</div>
<div className="top-bar-right">
<Link to="/login">Log in</Link>
</div>
</div>
{child.render()} // HERE IS THE CHILD TO RENDER
</div>
);
Base.propTypes = {
child: PropTypes.object.isRequired
};
export default Base;
Then, in app.jsx, where lies the ReactDom.render(), I have this :
import React from 'react';
import ReactDom from 'react-dom';
import injectTapEventPlugin from 'react-tap-event-plugin';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import {BrowserRouter, Switch, Route} from 'react-router-dom';
import LoginPag from './components/LoginPag.jsx';
import Base from './components/Base.jsx';
import HomePage from './components/HomePage.jsx';
// for MaterialUI to work properly
injectTapEventPlugin();
const TestLogin = (props) => {
return (<Base child={LoginPag} />);
};
const TestBase = (props) => {
return(<Base child={HomePage}/>)
};
ReactDom.render((<BrowserRouter><MuiThemeProvider muiTheme={getMuiTheme()}>
<div>
<Switch>
<Route exact path="/" component={TestBase} />
<Route exact path="/login" component={TestLogin}/>
</Switch>
</div>
</MuiThemeProvider>
</BrowserRouter>), document.getElementById('react-app'));
Finally, HomePage and LoginPag look alike and here's the HomePage.jsx :
import React from 'react';
import { Card, CardTitle } from 'material-ui/Card';
const HomePage = {
render() {
return (<Card className="container">
<CardTitle title="React Application" subtitle="This is the home page." />
</Card>);
}
};
export default HomePage;
My question now is : Isn't it possible to get rid of these abstractions TestLogin and TestBase ?
My final goal is to have something like this :
<Route exact path="/" component={Base(HomePage)} />, that is to say getting rid of the abstraction layer and directly render this in one line.
Thanks in advance.
EDIT: Thanks to anuragasaurus, I could achieve what I wanted. Can I do it with a class as well ? The class is declared as class LoginPage extends React.Component and has a render() method.
You can use render to display your component inline,
<Route exact path="/" render={()=><Base child={HomePage} />} />
<Route exact path="/login" render={()=><Base child={LoginPage} />}/>
With a simple object AND a class:
const Base = ({ child }) => (
<div>
<div className="top-bar">
<div className="top-bar-left">
<NavLink to="/">React App</NavLink>
</div>
<div className="top-bar-right">
<Link to="/login">Log in</Link>
</div>
</div>
{child}
</div>
);
And
const TestLogin = (props) => {
return (<Base child={<LoginPage/>} />);
};
const TestBase = (props) => {
return(<Base child={<HomePage}/>/>)
};
To answer for the entire question :
<Route exact path="/" render={()=><Base child={<HomePage/>} />} />
<Route exact path="/login" render={()=><Base child={<LoginPage/>} />}/>