Перенаправить React компонент формы при отправке. React Router v5.1 - PullRequest
0 голосов
/ 15 марта 2020

Цель - У меня есть форма, которая используется для обновления сведений о продукте. Я хочу перенаправить на главную страницу при отправке формы.

Проблема в том, что я отправляю данные формы из моего 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

Ответы [ 2 ]

0 голосов
/ 15 марта 2020

используйте this.props.history.push('/') для перенаправления на домашнюю страницу вместо

0 голосов
/ 15 марта 2020

Я думаю, что от вас требуется определенная ясность, поэтому, пожалуйста, предоставьте скрипку или что-то в этом роде.

В то же время, я предполагаю, что вам нужно перенаправить в форму отправки?

Если это так,

import { useHistory } from "react-router-dom"; 

и сделать

  let history = useHistory();
  function handleSubmit() {
    props.handleSubmit() // the one that comes from your App
    history.push("/home");
  }

Как только вы предоставите больше информации, я соответственно отредактирую ответ.

...