i'm trying to change text in p depends on which Route is enabled. I was trying to make this with switch statement, but honestly don't know how, any ideas?
import React from 'react';
import '../styles/Main.css'
import { Switch, Route } from 'react-router-dom';
import DaysWeather from '../pages/DaysWeather';
import WorldWeather from '../pages/WorldWeather'
import CurrentWeather from '../pages/CurrentWeather';
const Main = () => {
return (<>
<main>
<p>Sprawdź pogodę w swoim mieście</p>
<Switch>
<Route path="/" exact component={CurrentWeather} />
<Route path="/daysweather" exact component={DaysWeather} />
<Route path="/worldweather" exact component={WorldWeather} />
</Switch>
</main>
</>);
}
export default Main;
I think you were on to the right idea using a switch statement. This is my implementation:
/* Main.js */
import React, { useState, useEffect } from "react";
import { BrowserRouter, Route, Switch, Link } from "react-router-dom";
import "./styles.css";
import WorldWeather from "./components/WorldWeather";
import DaysWeather from "./components/DaysWeather";
import CurrentWeather from "./components/CurrentWeather";
function getParaText() {
const route = window.location.pathname;
switch (route) {
case "/":
return "Current Weather Header";
case "/daysweather":
return "Days Weather Header";
case "/worldweather":
return "World Weather Header";
}
}
export default function Main() {
const [paraText, setParaText] = useState(getParaText());
const changeOnNewRoute = () => {
setParaText(getParaText());
};
return (
<main>
<BrowserRouter>
<p>{paraText}</p>
<div>
<Link style={{ marginRight: "20px" }} to="/">
CurrentWeather
</Link>
<Link style={{ marginRight: "20px" }} to="/daysweather">
DaysWeather
</Link>
<Link style={{ marginRight: "20px" }} to="/worldweather">
WorldWeather
</Link>
</div>
<Switch>
<Route
exact
path="/"
render={props => (
<CurrentWeather changeOnNewRoute={changeOnNewRoute} />
)}
/>
<Route
exact
path="/daysweather"
render={props => (
<DaysWeather changeOnNewRoute={changeOnNewRoute} />
)}
/>
<Route
exact
path="/worldweather"
render={props => (
<WorldWeather changeOnNewRoute={changeOnNewRoute} />
)}
/>
</Switch>
</BrowserRouter>
</main>
);
}
/* Child Component */
import React, { useEffect } from "react";
const CurrentWeather = props => {
useEffect(() => {
props.changeOnNewRoute();
});
return <div>This is the CurrentWeather Component</div>;
};
export default CurrentWeather;
Edit: added the final implementation with state for future use
You can access to current route with props.location.pathname
<Router>
<div>
<Nav />
<hr />
<Switch>
<Route path="/" exact component={CurrentWeather} />
<Route path="/daysweather" exact component={DaysWeather} />
<Route path="/worldweather" exact component={WorldWeather} />
</Switch>
</div>
</Router>
With withRouter,You can get access to the history object’s properties
function Nav(props) {
return (
<div>
<h2>
Current Route : {props.location.pathname}
</h2>
</div>
);
}
export default withRouter(Nav);
look at this sample,could be helpfull
Related
I have an error and can not find any solution in google. The error appears when I want to go to a poduct page and press a button on home page to go to a product page and there I don't have any element rendered, I used React Route to user be able to go to product page and add it to a cart and suppose I did something wrong with providing path but not sure.
VM867:236 Matched leaf route at location "/2" does not have an element. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.
Here is a code for Item Element:
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
function Item() {
const { id } = useParams();
const [item, setItem] = useState([]);
const [loading, setLoading] = useState(false);
console.log("item", item);
// Fetching Data
useEffect(() => {
const fetchedData = async () => {
setLoading(true);
const response = await fetch(`https://fakestoreapi.com/products/${id}`);
const data = response.json();
setItem(data);
};
fetchedData();
}, []);
return (
<div className="container">
{loading ? (
<>
<h3>Loading.....</h3>
</>
) : (
<div className="container">
<p>{item.title}</p>
</div>
)}
</div>
);
}
export default Item;
And for App.js
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import ItemsComponent from "./Componets/ItemsComponent";
import Navbar from "./Componets/Navbar";
import Home from "./Componets/Home";
import Item from "./Componets/Item";
import About from "./Componets/About";
import AboutLink from "./Componets/AboutLink";
import Contact from "./Componets/Contact";
import Footer from "./Componets/Footer";
import "./App.css";
function App() {
return (
<>
<Router>
<Navbar />
<Routes>
<Route
exact
path="/"
element={
<>
<Home />
<ItemsComponent />
</>
}
/>
<Route exact path="/:id" component={<Item />} />
<Route exact path="/about" element={<About />} />
</Routes>
<AboutLink />
<Footer />
</Router>
</>
);
}
export default App;
It also affected all styling.
Maybe it's because you have
<Route exact path="/:id" component={<Item />} />
instead of
<Route exact path="/:id" element={<Item />} />
?
I think that instead of this
<Route exact path="/:id" component={<Item />} />
you want either of those
<Route exact path="/:id" component={Item} />
<Route exact path="/:id" element={<Item />} />
How to create a path that can handle zero, one, the other or both parameters at once (react router v5).
For example:
/offers /offers/q-shoes /offers/London /offers/London/q-shoes
I am trying to achieve it this way, unfortunately in this case the path /offers/London and /offers is not captured
import React from 'react';
import pathToRegexp from 'path-to-regexp';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { Home, Browse } from './Pages';
const re = pathToRegexp('/offers/:location?/q-:search?');
const App = () => (
<Router>
<Switch>
<Route path={re}>
<Browse />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
export default App;
According to documentation you can use string or array of strings as path.
pathToRegexp function returning a RegEx object so you cannot use it. Instead, you should use an array of strings, with the order being more specific to less specific.
import React from "react";
import {
BrowserRouter as Router,
Route,
Switch,
Link,
withRouter
} from "react-router-dom";
const Component = withRouter((props) => {
return (
<div>
<div>{props.title}</div>
<div>{JSON.stringify(props.match.params)}</div>
</div>
);
});
const Home = () => <Component title="Home" />;
const Browse = () => <Component title="Browse" />;
const NoMatch = () => <Component title="NoMatch" />;
const pathArray = ["/offers/:location?/q-:search?", "/offers/:location?"];
const App = () => (
<Router>
<div style={{ display: "flex", flexDirection: "column" }}>
<Link to="/">/Home</Link>
<Link to="/offers">/offers</Link>
<Link to="/offers/q-shoes">/offers/q-shoes</Link>
<Link to="/offers/London">/offers/London</Link>
<Link to="/offers/London/q-shoes">/offers/London/q-shoes</Link>
</div>
<Switch>
<Route path={pathArray}>
<Browse />
</Route>
<Route path="/">
<Home />
</Route>
<Route>
<NoMatch />
</Route>
</Switch>
</Router>
);
export default App;
I am trying to pass the props in the route component, I know we cannot directly pass to that, so I used to render, but the props are still undefined in the child component.
import React from 'react';
//components
import Register from '../components/register/register';
import Login from "../components/login/login";
import ForgetPassword from '../components/forget-password/forget-password';
//redux
import {store} from "../redux/store";
import { connect } from 'react-redux';
import actions from "../redux/authentication/actions";
//react-router
import {BrowserRouter,Route,Switch} from "react-router-dom";
//antd
import "antd/dist/antd.css";
//css
import '../global/_global.scss';
function Authentication(props) {
console.log("PROPS", props)
return (
<div className="App">
<BrowserRouter>
{/*switch-component will render first that matches the includes path*/}
<Switch>
<Route path='/login' component={Login} />
<Route exact path='/' component={Login} />
<Route path='/register'
render={(props) => (
<Register {...props} check={props.registerUser} />
)}
/>
<Route path='/forget-password' component={ForgetPassword} />
</Switch>
</BrowserRouter>
</div>
);
}
function mapStateToProps(state){
return state.reducers;
}
export default connect(mapStateToProps, actions)(Authentication);
try using like this
return (
<Route
render={routeProps => (
<Component {...routeProps} />
)}
/>
);
instead of
return (
<Route
render={(routeProps) => (
<Component {...routeProps} />
)}
/>
);
I have some problem with react-router. It doesn't go to Edit page when I click on id. The id is in URL, but it doesn't do anything.
const Main = (props) => {
const { pathname } = props.location;
return (
<Fragment>
<div>
<div className="container">
<Header />
{pathname === "/create" ? <Create /> : null}
{pathname === '/edit/:id' ? <Edit /> : null}
{pathname === "/" ? <Home /> : null}
</div>
</div>
</Fragment>
);
};
export default withRouter(Main);
app.js:
require('./components/Index');
import React from 'react'
import ReactDOM from "react-dom"
import Index from "./components/Index";
import { BrowserRouter as Router} from "react-router-dom";
import { ToastContainer } from 'react-toastify';
const App =() =>{
}
if (document.getElementById('app')) {
ReactDOM.render(<Router> <Index /> <ToastContainer /></Router>, document.getElementById('app'));
}
index.js:
import React from "react";
import { Route, Switch } from "react-router-dom";
import Main from "./CRUD/Main";
import Create from "./CRUD/Create";
import Edit from "./CRUD/Edit";
import Home from "./CRUD/Home";
const Index = (props) => {
return (
<Main>
<Switch>
<Route path="/Create" component={Create} />
<Route path='/edit/:id' component={Edit} />
<Route exact path="/" component={Home} />
</Switch>
</Main>
);
};
export default Index;
I think main.js have some problems with pathname.
You don't need to do conditional rendering like you are doing in Main when using react-router. Switch will automatically render the first child <Route> or <Redirect> that will match the location.
Hence, you need to remove Main from your router component i.e. Index so that it looks like as shown below:
const Index = (props) => {
return (
<>
<NavBar /> {/* NavBar is optional, I just added for example */}
<Switch>
<Route path="/create" component={Create} />
<Route path="/edit/:id" component={Edit} />
<Route exact path="/" component={Home} />
</Switch>
</>
);
}
NavBar: (Links; just for example)
function NavBar() {
return (
<ul>
<li>
<Link to="/create">Go to create</Link>
</li>
<li>
<Link to="/edit/123">Go to edit with id = 123</Link>
</li>
<li>
<Link to="/">Go to home</Link>
</li>
</ul>
);
}
Now, when you click on the above links, it will automatically take you to the related component (as declared in routes i.e. Index). (no manually condition checking)
And example, to retrieve the URL param i.e. id in Edit component using useParams hook:
function Edit() {
const { id } = useParams<{ id: string }>(); // Remove <{ id: string }> if not using TypeScript
return <h2>Edit, {id}</h2>;
}
I'm trying to add routes to my application but for some reason there are two components being rendered to the page instead of just one.
My code looks like this (the relevant part):
import React from "react";
import Board from "./Components/Board";
import Navbar from "./Components/Navbar";
import TaskDetail from "./Components/TaskDetail";
import { LanesProvider } from "./Context/lanes.context";
import { TasksProvider } from "./Context/tasks.context";
import { BrowserRouter, Route, Switch } from "react-router-dom";
function App(props) {
const getTask = props => {
return <TaskDetail />;
};
return (
<>
<LanesProvider>
<TasksProvider>
<Navbar />
<Board />
<BrowserRouter>
<Switch>
<Route exact path="/" render={() => <Board />} />
<Route exact path="/board" render={() => <Board />} />
<Route exact path="/board/:taskName" render={() => getTask()} />
</Switch>
</BrowserRouter>
</TasksProvider>
</LanesProvider>
</>
);
}
Now basically when I'm navigating to "localhost/board/test" I would expect to just see the <TaskDetail/> component but instead I get the <Board /> AND <TaskDetail/>.
I didn't expect this to happen because of the exact boolean.
FYI: getTask() is only returning a component right now because I wanted to get the routes to work first before implementing further logic.
So far I could not find a solution to this.
Thank you in advance.
There is a <Board /> component outside your <BrowserRouter>
import React from "react";
import Board from "./Components/Board";
import Navbar from "./Components/Navbar";
import TaskDetail from "./Components/TaskDetail";
import { LanesProvider } from "./Context/lanes.context";
import { TasksProvider } from "./Context/tasks.context";
import { BrowserRouter, Route, Switch } from "react-router-dom";
function App(props) {
const getTask = props => {
return <TaskDetail />;
};
return (
<>
<LanesProvider>
<TasksProvider>
<Navbar />
<Board /> --> Remove this component from here
<BrowserRouter>
<Switch>
<Route exact path="/" render={() => <Board />} />
<Route exact path="/board" render={() => <Board />} />
<Route exact path="/board/:taskName" render={() => getTask()} />
</Switch>
</BrowserRouter>
</TasksProvider>
</LanesProvider>
</>
);
}