I am trying to figure out how to deal with this issue I am having with Material UI tabs. So I have a navbar with three different tabs. They all link to different url's but two of them are kind of similar in a way. Please see my code below:
<Tabs indicatorColor="primary" value={this.state.tabsValue} onChange={this.setTabsValue}>
<Tab className={classes.tab}
label="Main"
value="main"
component={Link}
to="/main"
classes={{ selected: classes.selectedTab, }} />
<Tab className={classes.tab}
label="Shoes"
value="shoes"
component={Link}
to="/sale/shoes"
classes={{ selected: classes.selectedTab, }} />
<Tab className={classes.tab}
label="Sale"
value="sale"
component={Link}
to="/sale"
classes={{ selected: classes.selectedTab }} />
</Tabs>
Here is where setTabsValue is handling change events:
setTabsValue = (obj, val) => {
this.setState({
tabsValue: val
});
};
And when there is a prop change, the setTabsValue is being set also here:
componentWillReceiveProps(nextProps) {
const newRoute = window.location.pathname.split('/')[2];
if (this.state.tabsValue !== newRoute) {
// update currentRoute for user ping
this.currentRoute = newRoute;
this.setState({
tabsValue: this.isMainRoute(newRoute)
});
}
As you may notice, the last two tabs have a common point where the word 'sale' is in the destination route. This caused an issue where if I were to try to visit shoes, the active tab underline would be under the sale tab. Im not sure what is causing the issue but my guess it has something to do with the routes being similar for the last two tabs.
Basically the only way where the active tab underline will show under 'Shoes' tab is when I am already on 'Sale' tab and I click 'Shoes'. After a prop update,(maybe after a few seconds) it will go back to the 'Sale' tab, which is weird.
Not sure what is going wrong here but any help is appreciate. Thanks!
Not sure if you are familiar, but React Router is a great solution for this that I use in all of my projects. https://v5.reactrouter.com/web/guides/quick-start
The following is an example of how you would go about making an application that would route you to components for each page.
export default function App() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/topics">
<Topics />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
Related
I am trying to make the actively selected navbar element change the background color via react state. However it does not fully work. When I click on an element in my navbar, it briefly gets styled correctly, but after a moment is reverted and my homepage element in the navbar becomes styled once more.
I have my (simplified) navbar code below:
function Navbar(props) {
const [clickedNavbarItem, setClickedNavbarItem] = React.useState("/");
return (
<ul>
<li>
<a
onClick={() => setClickedNavbarItem("/")}
className={clickedNavbarItem === "/" && "active"}
href="/"
>Solve
</a>
</li>
<li>
<a
onClick={() => setClickedNavbarItem("/about")}
className={clickedNavbarItem === "/about" && "active"}
href="/about"
>About
</a>
</li>
</ul>
)
}
To my understanding: When the user clicks a given anchor tag, it should run the onClick handler, which will re-assign the state. The navbar should then re-render, and the classname for the appropriately clicked item should have the "active" class, which should change the styling.
Additionally, the href should redirect the page as such (this is my React router code):
function App() {
return (
<>
<Navbar />
<Routes>
<Route path="/" element={<Solve />} />
<Route path="/about" element={<About />} />
<Route path="/explain" element={<Explain />} />
</Routes>
</>
)
}
I believe there is some interaction where the Navbar is getting reset perhaps when the href is activated, but I'm not entirely sure. Any help is appreciated.
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 have a project in react/typescript. I have a react router that looks like this
const Root = () => (
<>
<NavBar/>
<Router>
<Route path="/" component={Home} />
<Route path="/timer" component={TimerPage} />
</Router>
</>
);
And I have a material-ui appbar that looks like this
export default function NavBar() {
return (
<div>
<AppBar position="static">
<Tabs>
<Tab label="Timer" to="/timer" component={TimerPage} />
</Tabs>
</AppBar>
</div>
);
}
There are a few issues - first the 'to' in Tab doesn't compile. Secondly, how do I make these two components work together, given they do very similar things?
If you are trying to navigate to another page, wrap your tab component, let react-router handle with the navigation and navigate using react-router history,
<Tabs value={value} onChange={handleChange} aria-label="simple tabs
example">
<div onClick={() => history.push("/timer")}>
<Tab label="Timer" />
</div>
</Tabs>
<Router>
<Route path="/" component={Home} />
<Route path="/timer" component={TimerPage} />
</Router>
Route should be inside Switch. Also, if you write path="/" this means that whatever page you will visit will still go to "home" page. This is because react-router does something like "least" checking of routes. So, if you had defined path "/images", before "/images/1", both will route you to "/images". Instead you could change the order of these paths, or add exact keyword before the first one.
Take a look at example below.
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/timer" component={TimerPage} />
</Switch>
</Router>
or
<Router>
<Switch>
<Route path="/timer" component={TimerPage} />
<Route path="/" component={Home} />
</Switch>
</Router>
As for your second issue, you should put your AppBar (or div or any container) inside Router and assign Link to component property of Tab:
<Router>
<AppBar position="static">
<Tabs>
<Tab label="Timer" to="/timer" component={Link} />
</Tabs>
</AppBar>
</Router>
Keep in mind that Link component is imported from react-router and not from #mui.
i'm creating a simple movie app with React along with the movie rest api from TMDB. My Home page is welcoming the users showing the most popular movies trending nowadays. Now i would like to insert on the navbar a link to open another page that will show all the categories. I'm new to React Router so i might have doing it wrong, but when i try to redirect to the "category" component, the component will show on the same page without hiding the home page. That's the code:
<Router>
<Container maxWidth="xl">
<SearchAppBar handleChange={handleChange} query={query} />
<TitlebarGridList movies={movies} />
<Typography
component="div"
style={{ backgroundColor: "white", height: "100vh" }}
/>
</Container>
<Switch>
<Route exact path="/categories">
<Category />
</Route>
</Switch>
</Router>
If i type on the browser /category, the category component will showe behind the App homepage. How can i show only that one i want?
Thank you
try also to wrap the container with a route having / as path :
<Router>
<Switch>
<Route exact path="/">
<Container maxWidth="xl">
<SearchAppBar handleChange={handleChange} query={query} />
<TitlebarGridList movies={movies} />
<Typography
component="div"
style={{ backgroundColor: "white", height: "100vh" }}
/>
</Container>
</Route>
<Route exact path="/categories">
<Category />
</Route>
</Switch>
</Router>