Update URL after opening modal, ReactJS - javascript

I am kinda new to react and I would like to change the url once the user has clicked to open a modal window. There's also some data coming with the modal that I would like to reflect in the url. E.g. "my.app/folders/project-name/"
I tried some solutions with react router but I do not seem to get it just right...
Here is the modal that I wish could update the URL once it's opened.
{modalOpen ? (
<ProjectModal
projectName={target[0].project_name}
organization={target[0].organization}
avatar={target[0].organization_avatar}
client="xy"
selectedImg={target[0].images[0]}
gallery={target[0].images}
onClose={() => setModalOpen(false)}
/>
) : null}

Make sure you have this route mentioned in your Router. Something like this,
<Route path="parent" component="ParentComponent" />
<Route path="parent/modal" component="ParentComponent" />
Then you will have to use the history.push method while setting the variable to open the modal.
history.push('/parent/modal');
Hope my answer helps.
Checkout the docs for more info.

Related

How to use div like link to redirect to another page?

I need to make div which will act simulate to Link element, so when you click on it you navigate to another page.
Something like this
<Link to="/employees">
...
</Link>
But it has to be div.
I could use onClick but when I use it, I should use whole path https://pro.websire.com/employees. I don't want to use it because we have different versions of website.
So path should be exactly like in Link element
<div onClick={to('/employees')}>
...
</div>
Does anyone know is it possible to do ?
If you are using react router, you can programmatically navigate using the useNavigate hook. Inside your component, you need to do the following.
const LinkComponent = () =>{
const navigate = useNavigate()
return(<div onClick={() => navigate("/home")}>Link </div>)
}

React route like facebook

I'm trying to implement the route like facebook. Let me explain how some route works on Facebook, When a user is scrolling through his feed at home page, Url is example.com/ then if user clicked any photo in the feed a modal will appear over the feed and the url will change like example.com/photo/?urlparams. When user click the back button or close button, Modal hides itself and url back to previous home page example.com/ without re-rendering the feed.
What I tried is
<Route path='/' exact render={(props) => <PostLists {...props} scroll={scroll} /> } />
<Route path='/post/:id' render={(props) => <Single {...props} scroll={scroll}/> } />
PostLists component has infinte scroll so may have up to 90+ posts. Each post have Link to Single Component like below
<Link to={`/post/${props.post.slug}`} className={`post-title`}>{pTitle}</Link>
Everthing works fine like normal navigation. But I like to show this Single Component in the Modal over the PostsLits Component, by the same time URL should be changed like example.com/post/url-slug
So I replaced Link in the post's title as
<span onClick={titleClick} className={`post-title`}>{pTitle}</span>
const titleClick = () => {
props.toggle(true) //Modal Toggle
return window.history.pushState(null, null, `/post/${props.post.slug}`)
}
This works like what I expected but I'm using window history not the react's history so I cannot listen to the URL change from browser back button. If I click the back button URL changes to previous example.com/ But I'm unable to hide the Modal.
What I want is Every post can have (example.com/post/slug)seperate page to display their content, But when clicking the post from Home Page it should be displayed as Modal and url should change to their respective post url example.com/post/slug on clicking the back button modal should be hidden and PostLists should be displayed.

Gatsby server-side rendering of page with client-only routes, based on window location

I am working on a Gatsby project (a language learning blog) and am having trouble with an issue that only happens in production builds due to server-side rendering.
I programmatically generate a page for each blog post with the following scheme:
/posts/{post-name}. Each post can also have a number of subpaths that map to open tabs in the UI. For example, /posts/important-spanish-verbs/lesson would open the lesson tab. Each page has a matchPath property of /posts/{post-name}/*, and these are handled as client-only routes, implemented with reach-router.
With gatsby develop, the app works exactly as intended. When I visit /posts/some-post/podcast, it successfully opens to the podcast tab and I can see the active tab being set correctly.
The problem is that with gatsby build && gatsby serve, when I fresh-load a URL that directly navigates to a specific tab inside of the post (either manually visiting the whole URL or refreshing), the active tab is not set correctly in the UI.
The following snippet (highly simplified and condensed to demonstrate the issue) roughly outlines the problem:
function TabbedLayout({ children, basePath }) {
return (
<LocationProvider>
{({ location }) => {
return (
<Fragment>
<ul>
React.Children.map(children, (child, index) => {
const isActive = child.props.path === location.pathname
console.log(`tab ${child.props.path} active? ${isActive}`)
return <li className={isActive ? 'active' : 'inactive'}>{/* construct a link based on child props */}</li>
})
</ul>
<Router basepath={basePath}>
{children}
</Router>
</Fragment>
)
}}
</LocationProvider>
}
What happens when I run my code which uses the method demonstrated above in a production build (with SSR) is that when I visit for example posts/example-post/lesson:
The content is rendered correctly via Reach router (i.e. the content of the lesson tab is open)
The lesson tab has class inactive (an error)
In the console, I see tab /posts/example-post/lesson active? true printed, even though the CSS class didn't get updated!
I've tried everything I can think of to try to update the UI. As soon as I click a different tab and the window location changes without a refresh, everything updates fine and the active tab UI works as expected, but I just cannot seem to get it to re-render based on the isActive variable.
Does anyone know a way to fix or work around this issue?
Thanks!
I have managed to find a workaround for the issue, although it's a bit frustrating to not understand in detail why the problem is actually happening.
If I wrap the tab <li>s (which don't correctly show as active/inactive on first load with SSR) in a condition to check that we're in the browser, it works:
return typeof window !== 'undefined' && (
<li className={isActive ? 'active' : 'inactive'}>
{/* construct a link based on child props */}
</li>
)

Git Hub pages website not reflecting behavior from localhost

I have made a React web app and am hosting it through github pages, at this link here and I have a header which directs you to different pages.
When the site is opened it should default to the home page and the header titled "Home" should be highlighted orange. When you select a link, then that link becomes orange (pretty straightforward). When running locally it runs fine and reacts how I would expect.
But on GitHub Pages, it does not default to any link being "selected" when you go directly to the site, or refresh, but behaves fine when you are selecting different links after the intial load.
The gif below visually demonstrates the issue. Localhost is on the right, the real page is on the left:
https://imgur.com/a/YMZ0Hm3
I am obviously trying to fix it, but would also like to know exactly what is causing the issue because this seems like quite the little issue.
The source code can be found here.
The main routing code that is responsible is this section here from headerComponent
<Link onClick = {() => this.handleClick(Routes.HOME_PAGE) } className={this.state.url.toLowerCase() === Routes.HOME_PAGE.toLowerCase() ? 'selected':'nope'} to={Routes.HOME_PAGE}>Home</Link>
<Link onClick = {() => this.handleClick(Routes.RESUME_PAGE) } className={this.state.url.toLowerCase() === Routes.RESUME_PAGE.toLowerCase() ? 'selected':'nope'} to={Routes.RESUME_PAGE}>Resume</Link>
<Link onClick = {() => this.handleClick(Routes.COVER_LETTER_PAGE) } className={this.state.url.toLowerCase() === Routes.COVER_LETTER_PAGE.toLowerCase() ? 'selected':'nope'} to={Routes.COVER_LETTER_PAGE}>Cover Letter</Link>
Where handleClick(route) just sets this.state.url to the route passed in
I think I found the issue. In your state, you have:
this.state = {url: this.fullUrl.substr(this.fullUrl.lastIndexOf("/"), this.fullUrl.length - 1)};
This is cutting off everything except the last part of the url by default. So if the URL was https://dakotamaker.github.io/resume-site/resume, it would be setting state to /resume.
Then in your <Link>, you're checking if the url in state matches any of the routes. Assuming the process.env.PUBLIC_URL is https://dakotamaker.github.io/resume-site/, by on site load you're checking if /, /resume, /coverLetter, matches the full url equivalent. I.e.:
// before evaluation
className={this.state.url.toLowerCase() === Routes.HOME_PAGE.toLowerCase() ? 'selected':'nope'}
// after evaluation
className={'/resume' === 'https://dakotamaker.github.io/resume-site/resume' ? 'selected':'nope'}
But it works when you actually click on a link because your .handleClick function is setting the url in state to be the constant that you've defined in your Routes file. So if you click on the Resume page link, the url in state gets set to Routes.RESUME_PAGE. So when the Links check again whether it should add the class name, it's guaranteed that one link will always be selected.
So what you'll probably want to do is along the lines of not modifying the URL of the page the user first loads:
this.state = {url: this.fullUrl};
The reason is your local website is on root of localhost:3000 but your github page is on the subdirectory. To fix that, you should put 'basename' props into your Router component. It should be some thing like this
<Router history={browserHistory} basename={'resume-site'}>
<Route path="/" component={App} />
</Router>
I figured out that you have set your base name to env var. So just need to inject it while building by editing package.json:
"deploy": "PUBLIC_URL=resume-site gh-pages -d build"

AppBar contents are wrong after refresh or hitting back button

I am using ReactJS with Material-UI, which I am both quite new to using.
I have an AppBar component that is used as a main menu/navigation bar. I would like the title of the AppBar component to reflect the page I'm on. So if I press a button that routes the user to /login , I also want to change the title of the AppBar component to "Login". I have accomplished this but there seem to be some side effects so I doubt it's the proper practice.
At the moment, my AppBar component looks like so:
render() {
let MenuOptionsNotLogged = ({}) => (
<div>
<FlatButton
label="Log In"
containerElement={<Link to="/login" />}
secondary
linkButton
onClick={this.switchToLogin}
/>
</div>
);
return (
<div>
<MuiThemeProvider muiTheme={muiTheme}>
<div className="headerDiv">
<AppBar
className="appBar"
showMenuIconButton={this.state.appBarIcon}
title={this.state.appBarTitle}
iconElementRight={<MenuOptionsNotLogged />}
iconElementLeft={<IconButton><BackIcon /></IconButton>}
/>
</div>
</MuiThemeProvider>
</div>
);
In my constructor, I set the default state of the AppBar(the title and icon):
constructor(props, context) {
super(props, context);
this.switchToLogin = this.switchToLogin.bind(this);
this.state = {
appBarTitle: 'Home',
appBarIcon: false
};
}
And then I have a function which changes the title and icon when the user navigates to the Login page:
switchToLogin() {
this.setState({ appBarTitle: 'Log in' });
this.setState({ appBarIcon: true });
}
The problem
This 'works', but it has some problems if the user refreshes or hits the back button on their browser.
E.g. user navigates to /login, title changes to "Login", user refreshes browser. Then the user will be on /login but the title will reset to "Home".
Same problem with the back button. User can navigate to login, press back, and the title will stay as "Login" as opposed to "Home"
I see you have a Link component. My answer assumes you use react-router.
The problem is that your appBarTitle state is not mapped correctly with the current route.
Also when user refresh the browser, the state of components resets.
if you are not using reat-router 3.0, you can get access to the current route through this.context.location.pathname. You will need to read about how to use context here.
Then you can write a helper function to map pathname to the text you want to display: '/login' -> 'Login', '/' -> 'Home'.
Then the title of your AppBar can just be the value returned from the helper function. You no longer need to keep tract of it in the state.
Just to add, not relating to your question, Reactjs is a declarative style of programming, meaning that, 'switchToLogin then display login title' is discouraged. Tell the component what to render rather than how to.

Categories