I want to create routing for overlay modal with parent page in background. Just like in instagram.com , When you click create icon it takes u to "/create/select" while the parent page is still in background.
I tried to implement this in my own page, but it didn't seem to work, it renders the whole new page instead of parent page.
function Routes(){
return(
<Router>
<Switch>
<Route path = "/login" component = {LoginPage} />
<Route path = "/signup/name" component = {NamePage} />
<Route path = "/signup" component = { SignupPage } />
<MainContainer>
<Route path = "/" exact component = {HomePage} />
<Route path = "/explore" component = {Overlay} />
</MainContainer>
</Switch>
<Route path = "/create" children = {<Overlay />}/>
</Router>
)
}
function MainContainer(props: any){
return(
<userContext.Provider value = {currentUser}>
<div id = "main-container">
<NavComponent />
<div className = "main-container-right">
<HeaderComponent />
<main id = "container">
{props.children}
</main>
</div>
</div>
</userContext.Provider>
)
}
It works when I remove exact from the "/" route, but I want the router switch page in "/explore". Is there anything I am doing wrong here?
If it's overlaying the background (parent) component, do you really need to change the route path? If so, my answer may be incomplete.
For overlaying, just put the overlayed component inside the parent's render function. However, you can use the parent's state to decide whether the child/overlay gets rendered.
For example:
render() {
return (
{this.state.overlay === true && <Overlay />}
)
}
This uses a property in the state called overlay - which should likely be false by default. Then just use a function in the parent component to toggle this on/off. You can pass this toggle in to the overlay function in order to close out the overlay.
Related
I created a hook to toggle the visibility of a NavBar in my webpage (this is done in NavBar.jsx), I need to toggle the navbar elsewhere in my code, namely under Journey.jsx, can I pass these as params?
How should I approach this?
Here are the essential/boiled-down excerpts of my code if they can help....
App.jsx:
function App () {
return (
<Router hashType="hashbang">
<div className="App">
<NavBar />
<Switch>
<Route exact path="/l" component={() => <Lorem/>} />
<Route exact path="/j" component={() => <Journey/>} />
<Route exact path="/i" component={() => <Ipsum/>} />
</Switch>
</div>
</Router>
);
}
NavBar.jsx:
function NavBar () {
//I need access to these in Journey.jsx
const [sidebar, setSidebar] = useState(false);
const showSidebar = () => setSidebar(!sidebar);
return(
//elaborations about the menu where I use these functions/varariables
);
}
Journey.jsx:
function Journey () {
return (
//some unimportant divs
<button onClick={****I need access to showSidebar here****} ></button>
);
}
The way my NavBar is configured is so that the hamburger icon that toggles it is visible and usable from everywhere (including the journey page), but I want this specific button only on the journey page and nowhere else because, according to the theme of the website (by my team of designers) its supposed to be an aesthetic functionality
What can I do to make this happen? because I've tried re-creating the hook into App.jsx and try passing each func/var as props and then in Journey referencing it as props.sidebar etc. but that doesnt work either....
if the solution is to just pass as parameters, how exactly do I do that because I tried and it said something like it wasnt declared.
Any alternatives?
Thank you,
either you lift the state up to their closest common ancestor (app.js) and create a handleClick method in App.js (do the state change in App.js) and pass down the method with navBar current state as porps to Journey and NavBar.
or you use a Context check: https://reactjs.org/docs/context.html and https://reactjs.org/docs/hooks-reference.html#usecontext for further info.
The easiest way to share state is lifting state up to their common parent component, and then pass the state and some methods which change state by props, like this:
function App() {
// lift state up
const [sidebar, setSidebar] = useState(false);
const showSidebar = () => setSidebar(!sidebar);
return (
<Router hashType="hashbang">
<div className="App">
{/* pass state by props */}
<NavBar sidebar={sidebar} showSidebar={showSidebar} />
<Switch>
<Route exact path="/l" component={() => <Lorem />} />
{/* pass state by props */}
<Route exact path="/j" component={() => <Journey sidebar={sidebar} showSidebar={showSidebar} />} />
<Route exact path="/i" component={() => <Ipsum />} />
</Switch>
</div>
</Router>
);
}
function NavBar ({sidebar,showSidebar}) {
return(
//elaborations about the menu where I use these functions/varariables
);
}
function Journey ({sidebar,showSidebar}) {
return (
// use state from props
<button onClick={showSidebar} ></button>
);
}
Also you can use context to pass state deeply.
You can read the latest react docs beta, which describe very detailed:
React Doc Beta: Sharing State Between Components
React Doc Beta: Passing Data Deeply with Context
I hope it helpful for you!
//Route.js
<NestedRoutes base="/logs">
<Route>
<LogsMainPage updateQuery={setQuery} />
</Route>
<Route
path="/logs/detail"
component={props => {
return React.createElement(LogDetailsPage, {
currentMainPageQuery: query,
...props,
});
}}
/>
<Route
path={'/:rest*'}
component={params => <h1>Not Found {params.rest}</h1>}
/>
</NestedRoutes>
// NestedRoutes.js
const NestedRoutes = props => {
const router = useRouter();
const [parentLocation] = useLocation();
const nestedBase = `${router.base}${props.base}`;
// don't render anything outside of the scope
if (!parentLocation.startsWith(nestedBase)) return null;
// we need key to make sure the router will remount when base changed
return (
<Router base={nestedBase} key={nestedBase}>
{props.children}
</Router>
);
};
The problem is everytime the page render it always shown Not Found(main content is rendered ie: LogsMainPage) even though the url is correct. Tried digging but can't found how to fix this "not found" url. Is there any guide to set this up properly?
I've edit the example from docs on the "help center route" I put the same code to show Not Found
https://codesandbox.io/s/wouter-demo-nested-routes-forked-qmg6q
Fix your problem by following these steps.
Wrap your /help index page content using Route component.
Then wrap all your /help routes using the Switch component. It will make sure that only one route is rendered at a time like in React Router. (Resource - https://github.com/molefrog/wouter/blob/master/README.md#switch-)
<Scope base="/help">
<Switch>
<Route path="/topics">
<h1>Topics</h1>
<p> To be announced...</p>
</Route>
<Route path="/how-to">
<article>
<h1>How it all started?</h1>
<p></p>
<p></p>
</article>
</Route>
<Route path="/">
<div>
These are nested routes. Relative location: <CurrentLoc />
<ul>
<li>
<Link href="/topics">Topics</Link>
</li>
<li>
<Link href="/how-to">How to use?</Link>
</li>
</ul>
</div>
</Route> {/* Wrap the index page content */}
<Route path="/:rest*" component={() => <h1>Not Found</h1>} />
</Switch> {/* Wrap all the help routes */}
</Scope>
https://codesandbox.io/s/wouter-demo-nested-routes-4q9iv?file=/src/index.js
Let me know if you need further support.
I have a component tree like this:
-App
--UserList
---UserItem
---UserItem
---UserItem
--User
I'm not being able to pass user data from UserItem to User. This is what I have:
App.js
export default class App extends Component {
state = { users: [] }
componentDidMount() {// fetch and setState}
render() {
return (
<BrowserRouter>
<Route
exact
path="/"
render={() => <UserList users={this.state.users} />}
/>
</BrowserRouter>
)
}
}
UserList.js
export default function({ users }) {
return (
<div>
{users.map(user => (
<UserItem user={user} key={`${user.id}`} />
))}
</div>
)
}
This is where the problem is: I want to pass the data from the parent component to the child User component, instead of having to fetch the user data from the API again.
UserItem.js
export default function({ user }) {
return (
<div>
<Link to="/user">{user.name}</Link>
<Route path={`/user/${user.name}`} render={() => <User user={user} />} />
</div>
)
}
I'm not sure what you're trying to implement here. Your app renders the UserList when then route is /. The UserList renders a UserItem component for each user in the array. Each UserItem simply renders a route specific to every user, which will render the User component if that route is triggered.
But if I'm not mistaken, the UserList will not be rendered if the route is anything but /, so if someone accesses user/..., the inner routes won't actually exist.
Essentially, this app will not render anything.
If you remove the exact keyword from the route in App, I think you'll get the result you are looking for. In this case, opening /user/<USER_NAME> will render the User element for that user.
Your question is regarding passing props into a component through a route, and the mechanism you've used is correct.
<Route path={...} render={() => <User user={user} />} />
This is actually right. See the code linked below. On changing the route to /user/User1, you'll see the name of "User1" rendered in the app.
See the working code here: https://codesandbox.io/s/18w3393767
You should use this.props.users in the UserItem component
i'm not sure but could you pass props like below, here i pass props to render and then to User Component
<Route path={`/user/${user.name}`} render={(props) => <User user={user} {...props} />} />
export default function({ users }) {
return (
<div>
{ this.props.users.map(user => (
//mistake here this.props.users.map not users.map
<UserItem user={user} key={`${user.id}`} />
))}
</div>
)
}
I have a React-based web application that utilizes React Router to map pages to different URLs:
export const Container = () => (
<div>
<SideNav/>
<div>
<Switch>
<Route path="/login" component={LoginView} />
<Route path="/route1" component={RouteOne} />
<Route path="/route2" component={RouteTwo} />
</Switch>
</div>
</div>
)
When any route gets hit, the sidebar gets rendered as well as the appropriate view. However, I am trying to build the layout such that for certain routes (such as "login"), the SideNav doesn't get rendered and the component (in this case, LoginView) is the only thing that gets rendered. In other words, LoginView should take over the div and be the only child of the top div.
Is there anyway this can be done?
According to react-router docs:
path: string Any valid URL path that path-to-regexp understands.
path-to-regexp understand a string, array of strings, or a regular expression.
Array of routes:
State which routes will render the SideNav as well (Working Example):
<Route path={['/route1', '/route2']} component={SideNav} />
RegExp:
Another option is to show the SideNav only if the path doesn't contain a certain word (working example):
<Route path={/^(?!.*login).*$/} component={SideNav} />
And in your code:
export const Container = () => (
<div>
<Route path={['/route1', '/route2']} component={SideNav} />
<div>
<Switch>
<Route path="/login" component={LoginView} />
<Route path="/route1" component={RouteOne} />
<Route path="/route2" component={RouteTwo} />
</Switch>
</div>
</div>
)
Another approach (I am not sure about this but I faced the same problem and this is how I fixed it, but I admit it's less cleaner than what Ori Drori proposed):
In your SideNav component :
import React from "react";
import {useLocation} from "react-router"
export const SideNav = (props) => {
const location = useLocation();
const show = !location.pathname.includes("login");
return (
<>
{show && (<YourLoginComponentCode /> }
</>
)
}
I have a dropdown BasketContents component (as per this question), which fades in and out when a button is clicked. I also want it to close when a the route is changed by clicking a Link tag. I.e. if it's already open on the Checkout page, if I then click the Home page link I want it to automatically close without clicking the basket's close button.
My Routes.js is the root of the app:
render() {
return (
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Home} />
<Route path="/home" component={Home} />
<Route path="/checkout" component={Checkout} />
</Route>
</Router>
);
}
App.js looks in part like this:
render() {
const childrenWithProps = React.Children.map(
this.props.children,
child => {
return (
React.cloneElement(child, {
basket: this.state.basket
}
)
)
}
);
return (
<div className="main">
<HeaderSection basket={this.state.basket} />
<div className="content">
{childrenWithProps}
</div>
</div>
)
}
The Basket.js component contains the button:
constructor() {
super();
this.state = { open: false }
this.handleDropDown = this.handleDropDown.bind(this);
}
handleDropDown() {
this.setState({ open: !this.state.open })
}
render() {
return(
<div className="basket">
<button className="basketBtn" onClick={this.handleDropDown}>Toggle</button>
<BasketContents
contents={this.props.contents}
open={this.state.open}
/>
</div>
)
}
I did try adding onEnter to my routes but understandably that doesn't do much since it doesn't have access to the Basket's open state. I would ideally like to set the open state of Basket.js to false when changing route (i.e. when clicking on a Link component). Is this possible?
I found a solution that doesn't rely on context. The first thing I did, following the React docs, was to lift my basket state up from the Basket component to the App component. This made it easier to manipulate it from a central location.
Then, following a suggestion here, I listened for changes to the browserHistory in the componentWillMount hook in App:
componentWillMount() {
browserHistory.listen( () => {
this.setState({ basketOpen: false });
});
}
The result is that when the page changes the basket closes.