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
ponent to the main App
ponent 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
ponent.
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
}
}
ponentDidMount() {
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: []
}
}
ponentDidMount() {
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"
ponent={({ match }) => (
<EditForm
productId={parseInt(match.params.id)}
userCurrency={selectedCurrency}
allProducts={products}
updateProducts={this.updateProducts}
/>
)}
/>
<Route
path="/products/:id"
ponent={({ match }) => (
<SingleProduct
productId={parseInt(match.params.id)}
allProducts={this.getLocalProducts()}
userCurrency={selectedCurrency}
/>
)}
/>
<Route
path="/"
exact
ponent={() => (
<ProductList
allProducts={products}
userCurrency={selectedCurrency}
/>
)}
/>
</Switch>
<Footer />
</div>
</Router>
)
}
}
export default App
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
ponent to the main App
ponent 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
ponent.
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
}
}
ponentDidMount() {
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: []
}
}
ponentDidMount() {
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"
ponent={({ match }) => (
<EditForm
productId={parseInt(match.params.id)}
userCurrency={selectedCurrency}
allProducts={products}
updateProducts={this.updateProducts}
/>
)}
/>
<Route
path="/products/:id"
ponent={({ match }) => (
<SingleProduct
productId={parseInt(match.params.id)}
allProducts={this.getLocalProducts()}
userCurrency={selectedCurrency}
/>
)}
/>
<Route
path="/"
exact
ponent={() => (
<ProductList
allProducts={products}
userCurrency={selectedCurrency}
/>
)}
/>
</Switch>
<Footer />
</div>
</Router>
)
}
}
export default App
Share
Improve this question
edited Mar 15, 2020 at 10:48
Andypants
asked Mar 15, 2020 at 10:21
AndypantsAndypants
31 silver badge4 bronze badges
2
- 1 can you provide fiddle or code ? – heisenberg Commented Mar 15, 2020 at 10:23
- Have added code, cheers. – Andypants Commented Mar 15, 2020 at 10:50
2 Answers
Reset to default 3I 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 es from your App
history.push("/home");
}
Once you provide more info, I will correspondingly edit the answer.
use this.props.history.push('/')
to redirect to your homepage instead
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745312502a4622063.html
评论列表(0条)