Цель - У меня есть форма, которая используется для обновления сведений о продукте. Я хочу перенаправить на главную страницу при отправке формы.
Проблема в том, что я отправляю данные формы из моего Form
компонента в основной App
компонент, чтобы обновить список продуктов. Продукты находятся в моем состоянии App
и передаются в качестве опоры моему Form
, что вызывает повторную визуализацию компонента Form
.
Form
имеет флаг в состоянии, которое является установить в конструктор значение false: toHome: false
. Мой план состоит в том, чтобы использовать реактив Redirect
реагирующего маршрутизатора для запуска, когда флаг установлен в true.
В методе handleSubmit EditForm
есть setState({ toHome: true })
. Но ТАКЖЕ в handleSubmit - это метод (переданный от App
как реквизит) для обновления продуктов в состоянии App
.
TLDR -> Form
handleSubmit обновляет продукты -> Form
повторно отображает -> флаг перенаправления (toHome
), установленный на false в конструкторе -> перенаправление никогда не происходит.
У меня та же проблема, даже если я хочу добавить короткое сообщение об успехе. Я застрял на этом слишком долго.
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