Reputation: 3
The goal - I have a form that is used to update product details. I want to redirect to home on form submit.
The problem is that I'm sending form data up from my Form
component to the main App
component to update the list of products. The products are in my App
state, and passed as a prop to my Form
, which causes a re-render of the Form
component.
Form
has a flag in state that is set to false in the constructor: toHome: false
. My plan being to utilise react-router's Redirect
to fire when the flag is set to true.
In the EditForm
handleSubmit method there's a setState({ toHome: true })
. But ALSO in handleSubmit is the method (passed from App
as a prop) to update the products in App
state.
TLDR -> Form
handleSubmit updates products -> Form
re-renders -> redirect flag (toHome
) set to false in constructor -> redirect never happens.
I have the same problem even if I want to add a short success message. I've been stuck on this for wayyy too long.
EditForm.js
import React, { Component } from 'react'
import { Link, Redirect } from 'react-router-dom'
import PropTypes from 'prop-types'
class EditForm extends Component {
constructor(props) {
super(props)
this.state = {
product: {
id: '',
name: '',
description: '',
price: {
base: '',
amount: ''
},
relatedProducts: []
},
productIndex: '',
toHome: false
}
}
componentDidMount() {
const { productId, allProducts } = this.props
const thisProduct = this.findProduct(productId, allProducts)
const thisIndex = this.findIndex(productId, allProducts)
this.setState({ product: { ...thisProduct }, productIndex: thisIndex })
}
.........
handleSubmit(e) {
e.preventDefault()
const newAllProducts = this.mergeProducts()
// this is the method that's firing the re-render
this.props.updateProducts(newAllProducts)
// and here is the ill-fated setState
this.setState({ toHome: true })
}
render() {
const { id, name, description, price, toHome } = this.state.product
console.log(this.state.toHome)
if (toHome) {
return <Redirect to="/" />
}
return (
<div className="edit-form">
....form...
</div>
</div>
)
}
}
EditForm.propTypes = {
productId: PropTypes.number.isRequired,
allProducts: PropTypes.array.isRequired,
userCurrency: PropTypes.string.isRequired,
updateProducts: PropTypes.func.isRequired
}
export default EditForm
App.js
import React, { Component } from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
import ProductList from './ProductList'
import SingleProduct from './SingleProduct'
import Header from './Header'
import EditForm from './EditForm'
import Footer from './Footer'
import allProducts from '../data/products.json'
import '../scss/index.scss'
class App extends Component {
constructor() {
super()
this.state = {
selectedCurrency: 'AUD',
products: []
}
}
componentDidMount() {
this.setState({
products: this.getLocalProducts()
})
}
// Checks localStorage for existing product data.
// If none, initiates localStorage with raw products data
// and returns raw products to be added to state.
getLocalProducts() {
const localData = localStorage.getItem('allProducts')
if (localData !== 'undefined' && localData !== null) {
return JSON.parse(localData)
} else {
localStorage.setItem('allProducts', JSON.stringify(allProducts))
return allProducts
}
}
// Updates localStorage and state.
updateProducts = data => {
localStorage.setItem('allProducts', JSON.stringify(data))
this.setState({ products: data })
}
clearRedirect = () => {
this.setState({ redirect: false })
}
handleCurrencyChange(e) {
this.setState({ selectedCurrency: e.value })
}
render() {
const { selectedCurrency, products } = this.state
return (
<Router>
<div className="app">
<Header
handleChange={e => this.handleCurrencyChange(e)}
userCurrency={selectedCurrency}
/>
<Switch>
<Route
path="/products/:id/edit"
component={({ match }) => (
<EditForm
productId={parseInt(match.params.id)}
userCurrency={selectedCurrency}
allProducts={products}
updateProducts={this.updateProducts}
/>
)}
/>
<Route
path="/products/:id"
component={({ match }) => (
<SingleProduct
productId={parseInt(match.params.id)}
allProducts={this.getLocalProducts()}
userCurrency={selectedCurrency}
/>
)}
/>
<Route
path="/"
exact
component={() => (
<ProductList
allProducts={products}
userCurrency={selectedCurrency}
/>
)}
/>
</Switch>
<Footer />
</div>
</Router>
)
}
}
export default App
Upvotes: 0
Views: 7006
Reputation: 169
use this.props.history.push('/')
to redirect to your homepage instead
Upvotes: 1
Reputation: 420
I think there is some clarity needed from you regarding the impl, so please provide a fiddle or something.
In the meantime, what I am guessing is, that you need to redirect on your form submit?
If that is the case,
import { useHistory } from "react-router-dom";
and do
let history = useHistory();
function handleSubmit() {
props.handleSubmit() // the one that comes from your App
history.push("/home");
}
Once you provide more info, I will correspondingly edit the answer.
Upvotes: 3