简体   繁体   English

反应,通过 function 作为不同组件中的道具

[英]React, pass function as prop in different component

I have a demo here在这里有一个演示

I have a simple list of products and a cart that I would like to add the products to.我有一个简单的产品列表和一个我想将产品添加到其中的购物车。

The Products and Cart are separate components in the index file. ProductsCart是索引文件中的独立组件。

I have the function to add the products to the cart in the Products components but how do I pass this to the Cart component that is outside the Products component.我有 function 将产品添加到 Products 组件中的购物车,但是如何将其传递给 Products 组件之外的 Cart 组件。

import React, { useState } from "react";
import { render } from "react-dom";
import Cart from "./Cart";
import Products from "./Products";
import "./style.css";

const App = () => {
  return (
    <div>
      <Products />
      <Cart />
    </div>
  );
};

render(<App />, document.getElementById("root"));

https://stackblitz.com/edit/react-ts-txpsds https://stackblitz.com/edit/react-ts-txpsds

 // index.tsx import React from "react"; import { render } from "react-dom"; import Cart from "./Cart"; import { CartProvider } from "./context"; import Products from "./Products"; import "./style.css"; const App = () => { return ( <CartProvider> <div> <Products /> <Cart /> </div> </CartProvider> ); }; render(<App />, document.getElementById("root"));

 // Products.tsx import React, { createContext, useCallback, useContext, useState } from "react"; import { AddCartContext } from "./context"; import { IProduct } from "./interface"; const Products = () => { const addItems = useContext(AddCartContext); const items = [ { id: 1, name: "Product One", price: 20 }, { id: 2, name: "Product Two", price: 56 }, { id: 3, name: "Product Three", price: 13 } ]; const handleClick = ( e: React.MouseEvent<HTMLInputElement, MouseEvent>, item: IProduct ) => { e.preventDefault(); addItems(item); }; const listItems = items.map(item => ( <div key={item.id}> {`${item.name}: £${item.price}`} <input type="submit" value="+" onClick={e => handleClick(e, item)} /> </div> )); return ( <div> <div> <h2>Products</h2> {listItems} </div> </div> ); }; export default Products;

 const Cart = () => { const items = useContext(CartContext); const cartItems = items.map((item, index) => ( <div key={index}>{`${item.name}: £${item.price}`}</div> )); return ( <div> <h2>Cart</h2> {cartItems} </div> ); };

 // context.tsx import React, { createContext, useCallback, useRef, useState } from "react"; export const CartContext = createContext([]); export const AddCartContext = createContext(item => {}); export function CartProvider(props) { const [items, setItems] = useState([]); const itemsRef = useRef(items); itemsRef.current = items; return ( <AddCartContext.Provider value={useCallback(item => { setItems([...itemsRef.current, item]); }, [])} > <CartContext.Provider value={items}> {props.children} </CartContext.Provider> </AddCartContext.Provider> ); }

If you want to share a property or function between multiple components you need to put that property or function in closest parent of those components so you can pass them as props .如果您想在多个components之间共享一个propertyfunction您需要将该propertyfunction放在这些components的最近parent级中,以便您可以将它们作为props传递。

In your case try to add your function to your App Component and then pass the function to both Products and Cart Components在您的情况下,尝试将您的function添加到您的App组件,然后将 function 传递给ProductsCart组件

There are 2 work-arounds for your problem.您的问题有两种解决方法。

  1. You can make the Cart component as the child component of Products through which you can pass the addToCart() as Props to Cart.您可以将Cart组件作为 Products 的子组件,通过它您可以将addToCart()作为 Props 传递给 Cart。 [but it is not meaningful] [但没有意义]

  2. You can bring the state from Product Component to App ie make the App as a stateful component and for products and Cart , make them as statelesss.您可以将state从 Product Component 带到App ,即将App作为有状态组件,而对于products and Cart ,将它们设为无状态。 Pass the data and methods as props.将数据和方法作为道具传递。

For the second option, check the link .对于第二个选项,请检查链接

Take a look at the react docs for Lifting state up .看一下Lifting state up的反应文档。

Move your cart state up into the closest common ancestor - App .将您的cart state 向上移动到最近的共同祖先App中。

From App , pass cart and setCart as props into both Products and Cart as needed.App中,根据需要将cartsetCart作为道具传递给ProductsCart

import React, { useState, Dispatch, SetStateAction } from "react";
import { render } from "react-dom";

interface IProduct {
  id: number;
  name: string;
  price: number;
}

const App = () => {
  const [cart, setCart] = useState<IProduct[]>([]);
  return (
    <div>
      <Products cart={cart} setCart={setCart} />
      <Cart cart={cart} />
    </div>
  );
};

function Cart({ cart = [] }: { cart: IProduct[] }) {
  return (
    <div>
      <h2>Cart</h2>
      {cart.map(item => (
        <div>{`${item.name}: £${item.price}`}</div>
      ))}
    </div>
  );
}

function Products({
  cart,
  setCart
}: {
  cart: IProduct[];
  setCart: Dispatch<SetStateAction<IProduct[]>>;
}) {
    const items: IProduct[] = [{id: 1,name: "Product One",price: 20},{id: 2,name: "Product Two",price: 56},{id: 3,name: "Product Three",price: 13}];

  const handleClick = (
    e: React.MouseEvent<HTMLInputElement, MouseEvent>,
    item: IProduct
  ) => {
    e.preventDefault();
    setCart([...cart, item]);
  };

  return (
    <div>
      <div>
        <h2>Products</h2>
        {items.map(item => (
          <div>
            {`${item.name}: £${item.price}`}
            <input
              type="submit"
              value="+"
              onClick={e => setCart([...cart, item])}
            />
          </div>
        ))}
      </div>
    </div>
  );
}

render(<App />, document.getElementById("root"));

Stackblitz 堆栈闪电战

Keep a common items variable and a function addItems in App.tsx and you need to pass this function as prop to Product component which when adds a product will call this same function in App.tsx file and update the items list.And this items list can be passed to the Cart component. Keep a common items variable and a function addItems in App.tsx and you need to pass this function as prop to Product component which when adds a product will call this same function in App.tsx file and update the items list.And this items list可以传递给 Cart 组件。 Here check this live demo: https://stackblitz.com/edit/react-ts-qq5cea?file=index.tsx在这里查看这个现场演示: https://stackblitz.com/edit/react-ts-qq5cea?file=index.tsx

I improved your code a little, the main thing that needed to be done was to move the state to a higher level我稍微改进了你的代码,需要做的主要事情是将 state 移动到更高的级别

在此处输入图像描述

https://stackblitz.com/edit/react-ts-iicy7v?file=Shop.tsx https://stackblitz.com/edit/react-ts-iicy7v?file=Shop.tsx

const App = () => {
  return (
    <div>
      <Shop Products={Products} Cart={Cart} />
    </div>
  );
};

move logic to Shop:将逻辑移动到商店:

const Shop = ({ Products, Cart }) => {
  const [cart, setCart] = useState([]);

  const addToCart = (item: IProduct) => {
    setCart([...cart, item]);
  };

  const removeFromCart = (item: IProduct) => {
    const itemWillBeRemoved = cart.find(e => e.id === item.id);
    const index = cart.indexOf(itemWillBeRemoved);
    const newCart = [...cart];
    newCart.splice(index, 1);
    setCart(newCart);
  };

  const items = [
    {
      id: 1,
      name: "Product One",
      price: 20
    },
    {
      id: 2,
      name: "Product Two",
      price: 56
    },
    {
      id: 3,
      name: "Product Three",
      price: 13
    }
  ];

  return (
    <div>
      <Products items={items} addToCart={addToCart} />
      <Cart items={cart} removeFromCart={removeFromCart} />
    </div>
  );
};

But the best way - use State Management但最好的办法——使用 State 管理

Redux Redux 雷迪克斯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM