React router - url changes but not the view - javascript

I know this question is asked alot... I just have a specific scenario which isn't working.
I'm using Ant design AutoComplete component. For the onSelect I parse various values and then do a this.props.history.push(url) which works perfectly fine. The route is picked up and the view changes
One of the other actions I want to perform though is that when someone types into the autocomplete field and hit the enter key, it should go to my search page. The url does change, but the page doesnt redirect. If I hit F5 to refresh the page, it does open on the correct component.
<AutoComplete
dropdownClassName="search-dropdown"
dataSource={optionsB}
size={this.props.size}
onSelect={this.onSelectOption}
onSearch={this.props.handleSearchDashboard}
labelInValue
optionLabelProp="option"
className="searchArea"
defaultActiveFirstOption={false}
>
<Input
ref={input => {
this.searchBar = input;
}}
onPressEnter={e => this.goTo(e)}
/>
</AutoComplete>
And here is the goTo():
goTo = e => {
e.preventDefault();
e.stopPropagation();
const url = `/search/${e.target.value}`;
console.log("url", url);
this.props.history.push(url);
};
Any suggestions as to what might be happening here?

Related

Getting a page to reload where it was when back or forward button was clicked

I have this page that has two tables. The left table is a list of links that point to items in the right table using A href='#itemid' with the corresponding A id='itemid' in the right table. It works fine when you're just clicking links in the left table, but if I click the back or forward button the page reloads but doesn't return to the position it was in. The page URL includes the #itemid, so I don't understand why the page doesn't return to that position when the back or forward button is clicked. Also, the first load is just the webpage name without a hashtag, so I also need to know how to tell the browser to reload the page with both tables at the top. Currently, the only way I can get it to cooperate is by holding SHIFT and clicking the refresh button.
I have tried every refresh example I can find and none of them work.
META http-equiv='refresh' content='0'
This was disastrous, just kept constantly refreshing the page.
window.location,refresh();
document.location.refresh();
location.refresh();
All of those in a unLoad() attribute in the BODY tag, with and without true as the argument to the refresh function. I really don't want my web host's server constantly having to serve the page anyway, so true isn't an option even if it did work.
I am out of ideas. I also understand that the history is a single doubly-linked list and the forward and back buttons just move through the list in each direction, but you would think the action would result in the page being reloaded the way it looked the last time you were on that page, not like you're still on the page you were last on.
You need to use the history API, to push and pop states according to your needs.
Every time you click one of your links, you need to push a state and a location so that when you press the back button, that state is restored with the given location.
Below is an example on how you might use it. I would not recommend managing the whole page content with innerHTML. This is just done for simplicity. What you are doing in the callback and with the state, and under what circumstances you use saveState to push extra state, is up to you.
const router = (hook = console.log) => {
window.onpopstate = ({ state }) => hook(new URL(window.location.href), state);
hook(new URL(window.location.href));
return {
anchorHandler: e => {
e.preventDefault();
window.history.pushState(null, "", e.target.href);
hook(new URL(e.target.href));
return false;
},
saveState: (state, href = window.location.href) => {
window.history.pushState(state, "", href);
}
};
};
const locations = {
"/": (state) => `<h1>Home</h1>
<p>Type something in this input. If you blur it, it will be saved as state.
Now you can navigate back and forth to remove/restore it. <br />
For example, type something and navigate to the about page. Then press the back button.
</p>
<br />
<input
value="${state?.text || ''}"
onblur="saveState({text: this.value})"
/>
`,
"/about": (state) => `<h1>About</h1>`,
"/contact": (state) => `<h1>Contact</h1>`,
}
pageContent = document.getElementById("page-content");
const { saveState, anchorHandler } = router((location, state) =>
pageContent.innerHTML = locations[location.pathname]
? locations[location.pathname](state)
: locations["/"](state)
);
document
.querySelectorAll("a")
.forEach(a => a.addEventListener("click", anchorHandler));
<nav>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</nav>
<main>
<div id="page-content"></div>
</main>
I cannot show it as snippet because, SO, as security limitations around the usage of the history API. You can check pull this repo and run it locally https://github.com/bluebrown/spa-router-example, or visit this page where I have deployed that repo, https://spa-router-example.pages.dev/.

track form changes when user leaving page/refreshing

I have a form which is written using formik and react-hooks. I am trying get recommendations on how to track a form change when user clicks home button or page refresh/reload?
I have tried, browser history method to trigger a modal to show unsaved changes
const unlisten = browserHistory.listen( location => {
//trigger modal here
});
But this seems to doesn't work. Also I am using react-router...if any suggestions using that will be helpful.
I am all done storing formvalues into a state using useState and setState,
I have a modal to show when exit button is clicked on form to track form changes but I am not sure how to detect outside of form.
I will put this here as a posible workaround to the question.
When you update your form in your handleChange method (whatever it is),you can also update user localstorage. With this approach you can check when page loads if there is some values in storage from older sessions or before.
Setting Values:
this.setState({ item1: value }, () => {
localStorage.setItem('myForm', JSON.stringify(this.state));
});
Getting values:
componentDidMount() {
const storedValues = JSON.parse(localStorage.getItem('myForm'))
this.setState({...storedValues});
}
Restore Data:
In your onSubmit method remember to clear localStorage
localStorage.removeItem('myForm');
I'm using react-router-navigation-prompt for exactly that purpose, it's made for react router. Just add this component inside your <Form/> / <form/>,
<NavigationPrompt
when={formProps.dirty}>
{({ isActive, onConfirm, onCancel }) => {
if (isActive) {
return (
<ConfirmationPopUp
isOpen
onConfirm={onConfirm}
onCancel={onCancel}
/>
);
}
}}
</NavigationPrompt>

React Router HashRouter inserting a ? before # in url

I'm getting some strange behaviour with react/redux/react-router on Chrome. I have a component that looks like this:
const PageHeader = withRouter( props =>
<Form plain={true} onSubmit={() => props.history.push("/search")} >
{/*component stuff goes here */}
)
when I submit the form on Firefox it brings me to the correct url, i.e. http://myip/#/search. However on Chrome it brings me to the following url: http://myip/?#/search which for some reason is also refreshing the app so I lose all the state in my store. Has anyone observed this behaviour before?
(Also for the form component I'm using grommet)
Try suppressing the default submit behavior by changing your form to
<Form plain={true}
onSubmit={(e) => { e.preventDefault(); props.history.push("/search")}} >

Prevent component from unmounting - showing notification to users before opening other component

In my web app there is a form where users put in data. If they want to navigate to other component or back, I want to notify them that changes were made to form and show them confirmation dialog.
I know how to implement this if users click on back button on top of the form, but don't have any idea how to handle it when users click on sidebar menu options. (there is a sidebar with multiple links to other components - using react-router).
I have tried something using componentWillunmount() but no luck since component gets unmounted in any case.
If anyone has experience in this I would really need some help.
Try the routerWillLeave hook, here is a example from react-router's documentation:
const Home = withRouter(
React.createClass({
componentDidMount() {
this.props.router.setRouteLeaveHook(this.props.route, this.routerWillLeave)
},
routerWillLeave(nextLocation) {
// return false to prevent a transition w/o prompting the user,
// or return a string to allow the user to decide:
if (!this.state.isSaved)
return 'Your work is not saved! Are you sure you want to leave?'
},
// ...
})
)
https://github.com/ReactTraining/react-router/blob/master/docs/guides/ConfirmingNavigation.md

cannot get react-autocomplete item selection to trigger location change

I am using https://github.com/reactjs/react-autocomplete for easy navigation in my webapp. My usage is similar to the example seen here: https://github.com/reactjs/react-autocomplete/blob/master/examples/async-data/app.js
I want the browser to open a certain url (in the current window) when the user selects an item of the autocomplete.
My code for this looks like this:
onSelect={(value, item) => {
const url = "/customer/" + item.id;
//alert(url);
window.location = url;}
}
When an item is selected in the autocomplete (via cursor keys + enter key), the browser does not open the new url, which would be expected. Instead, the browser reloads the current page and adds a question mark at the end of the url.
The weird thing is: When I place an alert(url) before the window.location assignment, it works (the browser shows the alert first and then indeed opens the new url).
Any ideas what I am doing wrong? Thanks!
Ok found it, the react component was contained also a from. So hitting enter triggered a form submit in addition to triggering the onSelect callback.

Categories

Resources