简体   繁体   中英

Connecting states with different components

I have app with three different components. In ProductList component (comp.) I have a list of available products which are in shop. After I click on element from this list it should appears in ShoppingList comp. and it works after I applied states and transfer it in App comp. Then it is possible to remove from Shopping list after click on element and it works thanks to useEffect but user of app should be able to add new product whenever something had been deleted.

In my code when user add some products, next delete one or two and after that user want add somethind new application render from the beginning all array. Example of shopping list: appears: milk, bread, juice -> (user deleted juice) -> appears: milk, bread -> (user add butter) -> appears: milk, bread, juice, butter (should appear: milk, bread, butter).

In my code I have connected array which was filtered by deleted elements and send it to my ProductList to modify productsToBuy by using props.sendRemovedProductsToParent(productList). I thought if I delete elements from array at the beginning I should "repair" this array which I use call in useState. But it doesnt works.

Maybe I should unmount Shopping list after delete items and load again or I have to send "remove" function to ShoppingList component?

I have use function component and class component to practice.

App

 function App() {
  const [resultToDisplay, setResultToDisplay] = useState(``);
  const [resultRemoved, setResultRemoved] = useState(``);

  return (
    <div className={styles.appWrapper}>
      <AddProducts />
      <ProductsFilters />
      <div className={styles.columnsWrapper}>
        <ProductsList
          productsToDisplay={produkty}
          sendAddedProductsToParent={setResultToDisplay}
          resultRemoved={resultRemoved}
        />
        <ShopingList
          resultToDisplay={resultToDisplay}
          sendRemovedProductsToParent={setResultRemoved}
        />
      </div>
    </div>
  );
}

ShopingList

function ShopingList(props) {
  const [productList, setProductList] = useState(props.resultToDisplay);

  useEffect(() => {
    setProductList(props.resultToDisplay);
  }, [props.resultToDisplay]);

  function removeClick(e, index) {
    e.preventDefault();
    // console.log(index);
    // console.log(productList);
    setProductList(productList.filter((currProduct, i) => i !== index));
    props.sendRemovedProductsToParent(productList);
  }

  return (
    <div className={commonColumnsStyles.App}>
      <header className={commonColumnsStyles.AppHeader}>
        <p>Shoping List</p>
        <ul>
          {productList.length
            ? productList.map((currProduct, index) => (
                <li onContextMenu={(e) => removeClick(e, index)} key={index}>
                  {currProduct.nazwa}
                </li>
              ))
            : null}
        </ul>
      </header>
    </div>
  );
}

ProductList

class ProductsList extends React.Component {
  constructor(props) {
    super(props);
    this.state = { productsToBuy: this.props.resultRemoved };

    this.addProduct = this.addProduct.bind(this);
  }

  addProduct(index) {
    console.log(this.props.resultRemoved);
    const toBuy = Array.from(this.state.productsToBuy);
    toBuy.push(this.props.productsToDisplay[index]);
    this.setState({
      productsToBuy: toBuy,
    });
    this.props.sendAddedProductsToParent(toBuy);
    // console.log(toBuy);
  }

  render() {
    return (
      <div className={commonColumnsStyles.App}>
        <header className={commonColumnsStyles.AppHeader}>
          <p>Products list</p>
          <ul>
            {this.props.productsToDisplay.map((currProduct, index) => (
              <li key={index} onClick={() => this.addProduct(index)}>
                {currProduct.nazwa}
              </li>
            ))}
          </ul>
        </header>
      </div>
    );
  }
}

If you want to use some states in different components, you have to use a state management like React context or redux or others.

If your states are not too big and the logic is not complex you can implement it with react context.

it's a simple example for that. you can edit it and use in your app.

import React, { createContext, useState } from 'react';

const ProductContext = createContext();

function ProductProvider({ children }) {
  const [products, setProducts] = useState([]);

  function addProduct(product) {
    setProducts([...products, product]);
  }

  function deleteProduct(productId) {
    setProducts(products.filter(product => product.id !== productId));
  }

  return (
    <ProductContext.Provider value={{ products, addProduct, deleteProduct }}>
      {children}
    </ProductContext.Provider>
  );
}

export { ProductContext, ProductProvider };

and in the index you can wrap the app with context provider:

 <ProductProvider>
      <App />
 </ProductProvider>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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