I have 3 buttons that link to different pages. The main page is the only page that is supposed to display the buttons (App.js). I've created two more pages, table1.js, table2.js, table3.js that all display different things. My problem is, when I click either one of the buttons, it directs me to the right page (e.g. http://localhost:3000/table1) but the buttons are still being displayed. Is there a way I can do something like "remove buttons after user is directed to new page"?
class App extends Component {
render() {
return (
<div className="App">
<form className='button-container'>
<Router>
<div>
<Route exact path='/table1' component={table1}/>
<Link to="/table1" className='button'>
<button className='button' type="button">
Table 1
</button>
</Link>
</div>
<div>
<Route exact path='/table2' component={table2}/>
<Link to="/table2" className='button'>
<button className='button' type="button">
Table 2
</button>
</Link>
</div>
<div>
<Route exact path='/table3' component={table3}/>
<Link to="/table3" className='button'>
<button className='button' type="button">
Table 3
</button>
</Link>
</div>
</Router>
</form>
</div>
);
}
}
export default App;
You should probably separate you're routing buttons into a different component and only render the buttons based on a route or condition as well:
class Navigation extends Component {
render() {
return (
<form className="button-container">
<Link to="/table1" className="button">
<button className="button" type="button">
Table 1
</button>
</Link>
<Link to="/table2" className="button">
<button className="button" type="button">
Table 2
</button>
</Link>
<Link to="/table3" className="button">
<button className="button" type="button">
Table 3
</button>
</Link>
</form>
);
}
}
class App extends Component {
render() {
return (
<div className="App">
<Router>
<Switch> {/* only matches one route */}
<Route exact path="/table1" component={table1} />
<Route exact path="/table2" component={table2} />
<Route exact path="/table3" component={table3} />
<Route component={Navigation} /> {/* If no routes matched show Navigation */}
</Switch>
</Router>
</div>
);
}
}
export default App;
Related
i am trying to create a simple react project. it has a navbar, sidebar and the main content area.
first a home component is displayed.
home.js
import { useState } from "react";
import Navbar from "../navbar/navbar";
import Sidebar from "../sidebar/sidebar";
import "./style.css";
import { useSelector, useDispatch } from 'react-redux'
function Home() {
const sidebarOpen = useSelector((state) => state.sidebarOpenState);
return (
<>
<Navbar />
<div className="home-box d-flex">
{sidebarOpen && <div className="p-2 flex-fill"><Sidebar /></div>}
</div>
</>
);
}
export default Home;
my navbar has a button which will change state sidebarOpen.
my sidebar looks like this->
sidebar.js
import "./style.css";
import { Link } from "react-router-dom";
function Sidebar() {
return (
<div className="divSidebar">
<ul>
<li>
<Link to="/chess">
<img className="sidebar-img" src="images/sidebar/chess.png"></img>
<span className="sidebar-text">Chess</span>
</Link>
</li>
<li>
<Link to="/volleyball">
<img
className="sidebar-img"
src="images/sidebar/volleyball.png"
></img>
<span className="sidebar-text">Volleyball</span>
</Link>
</li>
<li>
<Link to="/football">
<img
className="sidebar-img"
src="images/sidebar/football.png"
></img>
<span className="sidebar-text">Football</span>
</Link>
</li>
<li>
<Link to="/tabletennis">
<img
className="sidebar-img"
src="images/sidebar/table-tennis.png"
></img>
<span className="sidebar-text">TableTennis</span>
</Link>
</li>
<li>
<Link to="/rugby">
<img className="sidebar-img" src="images/sidebar/rugby.png"></img>
<span className="sidebar-text">Rugby</span>
</Link>
</li>
</ul>
</div>
);
}
export default Sidebar;
when i click on chess, the respective component should be loaded.
chess.js
function Chess() {
return (
<>
<h1>chess</h1>
</>
);
}
export default Chess;
but the problem is my sidebar disappears. i only want the main content area to be changed nothing else. can someone help? let me know if u want to some more code.
---------edit
i have added console.log in two places. one is in the navbar where the toggle method is defined and another is in redux store where toggle state is defined. both the places onclick is working. i am able to see message but the sidebar is not getting rendered.
---------edit 2
App.js
import "./App.css";
import Navbar from "./components/navbar/navbar";
import { Route, Routes } from "react-router-dom";
import Chess from "./components/chess/chess";
import Volleyball from "./components/volleyball/volleyball";
import Football from "./components/football/football";
import TableTennis from "./components/tabletennis/tabletennis";
import Rugby from "./components/rugby/rugby";
import Home from "./components/home/home";
function App() {
return (
<div className="App">
<Routes>
<Route exact path="/" element={<Home />} />
<Route
path="/chess"
element={
<>
<Navbar />
<Chess />
</>
}
/>
<Route
path="/volleyball"
element={
<>
<Navbar />
<Volleyball />
</>
}
/>
<Route
path="/tabletennis"
element={
<>
<Navbar />
<TableTennis />
</>
}
/>
<Route
path="/football"
element={
<>
<Navbar />
<Football />
</>
}
/>
<Route
path="/rugby"
element={
<>
<Navbar />
<Rugby />
</>
}
/>
</Routes>
</div>
);
}
export default App;
When you click on Chess you navigate to "/chess"
So if u can't see your Navbar there, is because you have to render it there too.
Or, render the Navbar outside de Routes from BrowsterRouter.
We need to see the components rendering on "/chess" and the react-router-dom config on app.js (or on the top lvl you declare it)
----- edit ------
Ok, look this:
function App() {
return (
<BrowserRouter>
<NavBar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/test" element={<Test />} />
</Routes>
</BrowserRouter>
);
}
If you refactor your brower like this is gona be more clean to understand the code and even easy to escale.
As u see, the navBar is outside the Routes, so its gona be visible in all routes.
then you can have this:
-> one path -> one element
your Links on navbar (or sidebar or whatelse) are gona work good.
i found a way. i rendered <Sidebar /> again in all my child components.
like this->
chess.js
function Chess() {
const sidebarOpen = useSelector((state) => state.sidebarOpenState);
return (
{sidebarOpen && (
<div className="p-2 flex-fill">
<Sidebar />
</div>
)}
)
}
this way when i click on button the state is updated and sidebar is rendered automatically.
I need to create 2 multi-pages UIs(managementUI and documentUI) with different headers.
updates:
the header contains navigation buttons to open and display different subpage components between the header and footer of the UI it belongs to.
e.g. the ApiCardGrid component will be displayed in managementUI.
However, the subpage cannot open in the outlet between header and footer when I clicked button in navigation header.
in App.tsx
function App() {
const [totalApiData, setTotalApiData] = useState([]);
useEffect(() => {
axios.get("/api-documents").then((res) => {
setTotalApiData(res.data);
});
}, []);
return (
<>
<div className="App">
<Router>
<Routes>
<Route
path="/apiManagement"
element={<ManagementUI />}
>
<Route
path="apis"
element={<ApiCardGrid spacing={2} size={3} />}
/>
</Route>
<Route
path="/documents"
element={<DocumentUI />}
></Route>
</Routes>
</Router>
</div>
</>
);
}
(update) Following comments made by #Drew Reese, in ManagementUI, I put an Outlet between header and footer to render the contents of subpages like ApiCardGrid. In ManagementUI.tsx:
function ManagementUI() {
const [totalApiData, setTotalApiData] = useState([]);
useEffect(() => {
axios.get("/api-documents").then((res) => {
setTotalApiData(res.data);
});
}, []);
return (
<>
<div className="management-ui">
<div className="management-header">
<Header />
</div>
<div className="management-content">
<Outlet />
</div>
<div className="management-footer">
<Footer />
</div>
</div>
</>
);
}
(update)API List button that link to /apis to display ApiCardGrid component in the Header:
<Header>
<Toolbar
disableGutters
variant="dense"
id="header-primary-navigation"
className="gds-primary-navigation"
>
<nav>
<Button className="gds-button-primary-navigation" href="/apiManagement/apis">
API List
</Button>
<Link to="/apiManagement/apis">API List</Link>
<Button className="gds-button-primary-navigation" href="/apiInfo">
API Info
</Button>
<Button className="gds-button-primary-navigation" href="/addApis">
Add API
</Button>
<Button
className="gds-button-primary-navigation active"
href="/active"
>
active page
</Button>
</nav>
</Toolbar>
</ Header>
similar in Header2
However, when I open UI1 localhost:3000/UI1, the UI1 opened successfully, but if I click button subpage1 to try to display subpage1 in UI1, the console responds error:"No routes matched location "/subpage1".(solved following answer of #Drew Reese)
update:
When I input url http://localhost:3000/apiManagement, the UI shows up. However, when I clicked the API List button, the url jumps to http://localhost:3000/apiManagement/apis, but the subpage item not shows up. I opened inspect tool, but no errors in console.
The subpage(ApiGridCard) supposed to display like
When rendering components on routes that render descendent routes the parent routes necessarily need to append the path wildcard "*" to their paths to allow descendent path matching.
Example:
<Router>
<Routes>
<Route
path="/UI1/*"
element={<UI1 />}
/>
<Route
path="/UI2/*"
element={<UI2 />}
/>
</Routes>
</Router>
An alternative is to create UI layout routes that render the appropriate header component and an Outlet for nested routes to render their element into.
Example:
import { Outlet } from 'react-router-dom';
const UI1 = () => (
<div >
<div >
<Header1 />
</div>
<div >
<Outlet />
</div>
<div >
<Footer />
</div>
</div>
);
const UI2 = () => (
<div >
<div >
<Header2 />
</div>
<div >
<Outlet />
</div>
<div >
<Footer />
</div>
</div>
);
...
<Router>
<Routes>
<Route path="/UI1" element={<UI1 />}>
<Route path="subpage1" element={<Subpage1 />} /> // "/UI1/subpage1"
<Route path="subpage2" element={<Subpage2 />} /> // "/UI1/subpage2"
</Route>
<Route path="/UI2" element={<UI2 />}>
<Route path="subpage3" element={<Subpage3 />} /> // "/UI2/subpage3"
<Route path="subpage4" element={<Subpage4 />} /> // "/UI2/subpage4"
</Route>
</Routes>
</Router>
Codesandbox link here.
When a user clicks on a link, it should load the component in '/details'. However on click, it does load /details in the address bar but the component doesn't actually load. It only loads on going separately to /details manually in the address bar.
Routes.js
const Routes = () => {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={App} />
<Route exact path="/details" component={MachineDetail} />
</Switch>
</BrowserRouter>
);
};
MachineCard.js
export default function MachineCard({ image, title, weight, power }) {
return (
<>
<div className="col-lg-4">
<div className="card">
<Router>
<Link to="/details">
<img className="img-fluid" src={image} alt={title} />
<h2>{title}</h2>
</Link>
</Router>
<p>Operating weight: {weight}</p>
<p>Power: {power}</p>
</div>
</div>
</>
);
}
Any idea why it won't load the '/details' component in the browser?
This issue is that you have multiple routers in your app, but you only need one. Since you already have the router defined in your index file, you can go ahead and remove it from MachineCard.js.
Your MachineCard.js component can therefore be simplified to this:
export default function MachineCard({ image, title, weight, power }) {
return (
<>
<div className="col-lg-4">
<div className="card">
<Link to="/details">
<img className="img-fluid" src={image} alt={title} />
<h2>{title}</h2>
</Link>
<p>Operating weight: {weight}</p>
<p>Power: {power}</p>
</div>
</div>
</>
);
}
I think your problem is incorrect naming. In your route files you are using MachineDetail but you are exporting MachineCard.
I am new to React.
I have an app like this:
<>
<Header currentUser={currentUser}></Header>
<Menu items={menuitems}/>
<SubHeader currentUser={currentUser}></SubHeader>
<Breadcrumb items={crumbs} ></Breadcrumb>
<BrowserRouter history={history} >
<div >
<div className="container-fluid main-container">
<div className="row">
<div className="col-md-2"></div>
<div className="col-md-9">
<Switch>
{routes.map((rou,key) => {
return <PrivateRoute exact
path={rou.path}
key={key}
component={rou.component}
canAccess={rou.canAccess}
fallBackComponent={rou.fallBackComponent}/>;
})}
</Switch>
</div>
<div className="col-md-1"></div>
</div>
</div>
</div>
</BrowserRouter >
<Footer ></Footer>
</>
I would expect that every page change (using the Router), React would render only the part between tags , instead, every route change, I see that React reloads all components outside the router like <Header>, <Menu> and so on.
Am I doing something wrong?
In my case, i have 6 menu in my application. In header part i have 'Next' and 'back' buttons. If i click next button, it should navigate to next menu, for back button, it should navigate to previous page. and header.js is a seperate component. Code is attached below
app.js
render() {
return (
<Router>
<div className="h-100">
<Header />
<ContentNavigation />
<Switch>
<Route exact path='/' component={WelcomeMenu} />
<Route path='/principal' component={PrincipleMenu} />
<Route path='/mycar' component={MycarMenu} />
<Route path='/abc' component={abcMenu} />
<Route path='/ijkmenu' component={ijkMenu} />
<Route path='/xyzmenu' component={xyzMenu} />
</Switch>
</div>
</Router>
);
}
header.js
render() {
return (
<div className="header-right text-right header-text-pd-tp">
<span>
<i className ="icon-arrow-left prev-next-icon prev-icon"></i>
BACK
</span>
Current Chapter
<span>
NEXT
<i className="icon-arrow-right prev-next-icon next-icon" aria-hidden="true"></i>
</span>
</div>
)
}
This is one way to do routing
this.props.history.push({
pathname: '/your_route_path'
})
Multiple ways- you can navigate to other component.
1-using Link
import {Link} from 'react-router-dom'
<Link to="/ijkmenu">
NEXT
<i className="icon-arrow-right prev-next-icon next-icon" aria-hidden="true"></i>
</Link>
2-using this.props.history.push()
<span onClick={()=> this.props.history.push('/ijkmenu')}>
NEXT
<i className="icon-arrow-right prev-next-icon next-icon" aria-hidden="true"></i>
</span>