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")}} >
Related
I have been working with React for YEARS and have yet to encounter this phenomenon. If you can crack it, you'll be my hero forever 😂
The Setup
I have a shared component. It is a wrapper for some buttons that appear at the bottom of several different pages (most use cases are steps in a form. The last of those buttons ALWAYS throws a modal to cancel setup.
I am using the shared component in ALL the following use cases:
✔ The first page of a multi-step form. Works fine, throws modal.
✔ The second page of a multi-step form. Works fine, throws modal.
❌ The third page of a multi-step form. Fails. See description below
❌ The fourth page of a multi-step form. Fails
✔ The review page after the form is completed. Works fine again.
The component itself contains just a button that triggers a useState() setter locally, which toggles the modal open/closed.
The Problem
On the pages where it doesn't work, the component throws all the form values on the page up into the URL as a query string.
see image - green underlined portion is added on modal trigger
This triggers a page reload and of course things break.
Expected Result
I should be able to click "cancel" button and the modal pops. Nothing more, nothing less.
The (relevant) code
const IntakeLossButtons = ({
// PRIMARY BUTTON PROPS
buttonText,
onButtonClick,
buttonDisabled,
buttonSpinning,
buttonAriaLabel,
// CANCEL LINK AT BOTTOM
idToCancel,
saveAction,
onCancel
}) => {
const [showCancelModal, setShowCancelModal] = useState(false)
return (
<div className={styles.buttonsWrapper}>
<SpinnerButton
type="primary"
text={buttonText}
disabled={buttonDisabled}
spinning={buttonSpinning}
onClick={onButtonClick}
ariaLabel={buttonAriaLabel}
/>
<button
className="btnLink"
id="cancel-id"
tabIndex="0"
aria-label={translations.cancelBtnAria ||"Opens a modal to cancel your claim"}
color="secondary"
onClick={()=>setShowCancelModal(true)}
>
Cancel Setup
</button>
<CancelModal
isOpen={showCancelModal}
idToCancel={idToCancel}
onCancel={onCancel}
onSaveForLaterAction={saveAction}
onCloseModal={()=>setShowCancelModal(false)}
/>
</div>
)
}
export default IntakeLossButtons;
WTF?
What would cause this type of behavior? I have tried googling and reading what might cause this. I have logged everything I can log and I still don't know what is causing such a weird behavior.
Any ideas?
It sounds like maybe you forgot to do:
e.preventDefault();
inside the onSubmit handler of your form. In fact, it looks like you don't even have a <form> at all, just a <button> (one with no type attribute, which means it will default to being a submit button).
You need to wrap the button in a <form> with such a submit handler. If you don't do that, when you "submit the form" (ie. click the button) it will use all the form's inputs to generate a new URL, and then it will send you to do that URL.
This is the "default" behavior for forms in browsers. If you go to www.google.com, for instance, and search for "cute puppies", you'll see the URL changes to have ?q=cute+puppies, because Google relies on not preventing this default behavior.
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?
I'm making a React App and i'm struggling to get the basic functionality of components with state working. So far i've got a home page that connects to a registration page, when I click to the registration page I can handle user input. The registration is the class component I am trying to use state in so far.
I've set up a pretty basic process so far in this component just to see if it works. But when I click the button to console log what is currently stored the entire page reloads as if nothing has happened.
A very basic display of what it currently looks like:
import registerUser from './user.js';
class App extends Component {
render() {
return (
<Router>
<Route path='/register' component={registerUser}/>
</Router>
)
}
}
export default App;
class registerUser extends Component {
handleChange = () => {
console.log('test');
}
render() {
return (
<div>
<button onClick={this.handleChange}>Click</button>
</div>
)
}
export default registerUser;
But as I mentioned when I click the button the entire page just reloads as if nothing has occured. Am I missing something something basic as to why trying to use this method in a separate component reloads the entire app?
Any help would be greatly appreciated.
If the button is inside a form, then you must write e.preventDefault() in your handleChange function,
handleChange = (e) => {
e.preventDefault(); //It will prevent form submit
console.log('test');
}
Demo
Note: React component name should be in PascalCase, so just replace registerUser to RegisterUser.
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>
I set up a minimal Gatsby page to test when Gatsby re-renders, and I found out that just clicking a regular in-route (hash) anchor link, causes a re-render.
Why is that? Is there any way to prevent it?
Here is an example page:
const SomePage = props => {
console.log('RE-RENDERING PAGE');
return (
<>
Link that should not fire re-render;
</>
);
};
import { Link } from "gatsby"
const SomePage = props => {
return (
<Link to="#foo">Link that should not fire re-render</Link>;
);
};
<Link> will render a fully accessible anchor tag with the proper href.
React re-renders a lot. Since the entire page is wrapped in a Reach Router and you're using a non-memo functional component I'm not the slightest bit surprised you're getting a console message. I was under the impression you were trying to avoid a page reload, not prop-change-based React render.
If you'd like to prevent the re-render, you can use React.memo:
const SomePage = React.memo(() => <Link to="#foo">Text</Link>)