在 React 中提交表单后刷新页面

Refresh page after submit form in React

当我在输入中更改我的程序的价格并单击更新按钮时,一切都很好,价格发生了变化,但是当我刷新我的页面时,我出现了一个错误,即使我没有修改价格和我刚刷新页面就出现这个错误,我不明白为什么

这是错误的截图,你会在下面找到我的代码

应用程序

import React, { useState, useEffect } from 'react';
import './css/App.css';
import './css/Products.css';
import axios from 'axios';
import Navigation from './Components/Navigation';
import Products from './Components/Products';
import {BrowserRouter as Router, Route, Switch,} from 'react-router-dom';
import ProductsDetails from './Components/ProductsDetails';

export default function App() {
 
  const [productsData, setProductsData] = useState([]);
  
  useEffect(() => {
    axios.get("https://fakestoreapi.com/products?limit=7").then((res) => {
      setProductsData(res.data);
    });
  }, []);
  const updatePrice = (id, price) => {
    setProductsData((productsData) => 
      productsData.map((product) =>
        product.id === Number(id)
          ? {
              ...product,
              price: Number(price)
            }
          : product
      )
    );
  };

  return (
    <div className="App">
      <Router>
        <Navigation/>
        <Switch>        
          <Route 
            path="/products-details/:id"
            render={(props) => (
              <ProductsDetails 
                products={productsData}
                updatePrice={updatePrice}
                {...props}
              />
            )}
          />
          <Route path="/"> 
            <Products products={productsData}
            /> 
          </Route>
        </Switch>
      </Router>
    </div>
  );
}

产品

import React, { Component } from 'react';
import '../css/Products.css';
import './ProductsDetails'
import {Link} from 'react-router-dom'

export default class Products extends Component {
  render() {
    const listsProducts = this.props.products.map((listProduct) => {
      return (
        <tbody className="products__body" key={listProduct.id}>
          <tr>
          <td><Link to={{pathname: "/products-details/" + listProduct.id}}>{listProduct.title}</Link></td>
            <td><p className={`${listProduct.category==="men's clothing" ? "category__orange" : "category__green"}`}>{listProduct.category}</p></td>
            <td>{Number(listProduct.price).toFixed(2)}</td>
            <td>
              {Number(listProduct.price * 1.2).toFixed(2)} €
            </td>
          </tr>
        </tbody>
      );
    });
    return (
      <main className="products">
        <h1 className="products__title">Products management</h1>
        <table cellSpacing="0">
          <thead className="products__head">
            <tr>
              <th className="table--title">Product name</th>
              <th className="table--title">Category</th>
              <th className="table--title">Price</th>
              <th className="table--title">Price (including VAT)</th>
            </tr>
          </thead>
          {listsProducts}
        </table>
      </main>
    );
  }
}

产品详情

import React, { Component } from 'react'
import '../css/ProductsDetails.css'
import {AiOutlineArrowLeft} from "react-icons/ai";
import {Link} from 'react-router-dom'


export default class ProductsDetails extends Component {
    constructor(props) {
      super(props);
      // ajout de deux états l'id qu'on récupére de l'API et le prix qui vaut 0
      this.state = { 
          id: this.props.match.params.id, 
          price: 0
        };
    }
    
    // mise en place d'une méthode qui permet de modifier la valeur dans l'input texte 
    updatePrice = (e) => {
      console.log(e);
      this.setState({
        price: e.target.value
      });
    };
    
    /*
    mise en place d'une méthode qui permet au clique du bouton de changer le prix 
    grâce à la méthode "updatePrice ainsi que l'id et l'état du prix du produit
    */
    submitHandler = (e) => {
        // permet au clique du bouton que concerver localement la valeur modifiée 
        localStorage.setItem('price', this.state.price)
      e.preventDefault();
      const {
        match: {
          params: { id }
        }
      } = this.props;
      this.props.updatePrice(id, this.state.price);
      
    };

    // permet de garder la valeur modifiée au refresh de la page 
    componentDidMount() {
        const price = localStorage.getItem('price')
        this.setState({price});
    }
  
    render() {
      const {
        match: {
          params: { id }
        },
        products
      } = this.props;
      
      // Ajout d'une variable qui récupére le premier id trouvé dans le tableau "products"
      const listProduct = products.find((product) => product.id === Number(id));
  
      return (
        <div className="products__details">
          <Link to="/">
            <AiOutlineArrowLeft className="nav__arrow" />
          </Link>
          <h1 className="details__title">{listProduct.title}</h1>
          <div className="details__align--desk">
            <div className="details__img">
              <img
                className="product__img"
                src={listProduct.image}
                alt="Affichage du produit"
              />
            </div>
            <div className="products__align--desk">
              <h2 className="product__title">Description</h2>
              <p className="product__description">{listProduct.description}</p>
              <h2 className="product__title">Price</h2>
              <form className="form__price" onSubmit={this.submitHandler}>
                <input
                name="price"
                  className="input__price"
                  type="text"
                  defaultValue={Number(listProduct.price).toFixed(2)}
                  onChange={this.updatePrice}
                />
                <p>
                  Price (including VAT):{" "}
                  {Number(listProduct.price * 1.2).toFixed(2)} €
                </p>
                <br />
                <input
                  className="btn__update"
                  type="submit"
                  value="Update product"
                />
              </form>
            </div>
            <div className="category__align--desk">
              <h2 className="product__title">Category</h2>
              <p className={`${listProduct.category==="men's clothing" ? "category__orange" : "category__green"} product__category`}>{listProduct.category}</p>
            </div>
          </div>
        </div>
      );
    }
  }

预先感谢您的解释

我怀疑是因为当 listProductnull 时您没有覆盖状态。当它加载时,它会立即呈现,因为它正在获取您的产品数据,因此 products 可以为空,而 .find() 将 return 一个 null,然后您正在尝试在 null 时渲染 listProduct.title。理想情况下,您的渲染应该检查 listProduct 是否可用。

更好的是,让你的组件有一些状态,比如加载数据、显示数据、没有数据。

  <Card>
    { dataStatus === "Loaded" &&
      <Card.Title>{person.Name}</Card.Title>
    }
    { dataStatus === "Loading" &&
      <Card.Loader>Loading...</Card.Loader>
    }
    { dataStatus === "Error" &&
      <Card.Error>Sorry, we had an oopsie...</Card.Error>
    }
    { dataStatus === "Empty" &&
      <Card.Empty>Looks like we're missing something...</Card.Empty>
    }
  </Card>

这里有进一步的解释和代码示例:https://davidlozzi.com/2021/05/14/keeping-react-components-state-top-of-mind/