在ReactJS上的不同组件之间更新状态

时间:2019-05-20 18:24:22

标签: javascript reactjs

我是React JS的新手。我正在尝试将状态从另一个组件更新到另一个组件。 有人可以帮我解决吗?

当我点击 product.jsx 上的添加到购物车按钮时,我希望更新 header.jsx 上的状态总计

非常感谢

这是我的代码

index.jsx

  import React from 'react';
    import { render } from 'react-dom';
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

    import Header from './header';
    import Footer from './footer';
    import Posts from './posts';
    import Post from './post';
    import Products from './products';
    import Product from './product';
    import Page from './page';

    // Load the Sass file

    require('./style.scss');
    const App = () => (
        <div id="page-inner">
            <Header />
            <main id="content">
                <Switch>

                    <Route exact path={Settings.path + 'products/:product'} component={Product} />

                </Switch>
            </main>
            <Footer />
        </div>
    );

    // Routes
    const routes = (
        <Router>
            <Route path="/" component={App} />
        </Router>
    );

    render(
        (routes), document.getElementById('page')
    );

header.jsx

import React from "react";
import { Link } from "react-router-dom";

class Header extends React.Component {
constructor(props) {
        super(props);
        this.state = { products: [], total: 0 }
        var total = 0;
    this.cartUpdated = this.cartUpdated.bind(this)


      }

      componentDidMount() {

        //let cart = localStorage.getItem('total');
              //   this.setState({  total: 100  });



      }
      cartUpdated()
      {
                 this.setState({  total: cart+100  });


      }




render() {
    return (

          <div className="cart-icon p-3 m-auto">
            Cart/ Total: <span className=""><span className="cart">€</span>{this.state.total}</span><i className="fas fa-shopping-cart" />
          </div>

    );
  }
  }

export default Header;

product.jsx

import React from "react";
import NotFound from "./not-found";

import "react-image-gallery/styles/scss/image-gallery.scss";
import ImageGallery from 'react-image-gallery';



class Product extends React.Component {





  constructor(props) {
    super(props);
    this.state = { product: {},  total: 0
};

    // ACTIONS
// addToCart
     this.addToCart = this.addToCart.bind(this);





  }
  addToCart() 
  {
        this.props.cartUpdated;

     /*
        let total = localStorage.getItem('total') 
                      ? JSON.parse(localStorage.getItem('total')) : {};

        localStorage.setItem('total', 100); */

  }



  componentDidMount() {


          this.fetchData();


  }

  fetchData = () => {
    .......
  };

  renderProduct() {
     if (this.state.product.images) {
 const images = [];
 if (this.state.product) {

   this.state.product.images.map((image, i) => {  
    var new_image = {"original":image, "thumbnail":image}  ; 
          images.push(new_image);
        });
 }




    return (

      <div className="col-md-12">
      <div className="row">
        <div className="col-md-6">
              <ImageGallery items={images} showPlayButton={false} showFullscreenButton={false} thumbnailPosition="left" />
           </div>
                <div className="col-md-6">
                <h4 className="card-title">{this.state.product.name}</h4>
            <p className="card-text">
              <strike>${this.state.product.regular_price}</strike>{" "}
              <u>${this.state.product.sale_price}</u>
            </p>
            <p className="card-text">
              <small className="text-muted">
                {this.state.product.stock_quantity} in stock
              </small>
            </p>
            <p
              className="card-text"
              dangerouslySetInnerHTML={{
                __html: this.state.product.description
              }}
            />
            <div className="superflex add_to_cart_wrapper">
  <button type="submit" name="add-to-cart" value={93} className="add_to_cart btn btn-success alt" onClick={this.props.cartUpdated}>Add to cart</button>
</div>
</div>
</div>
      </div>
    );
  }
  }

  renderEmpty() {
    return <NotFound />;
  }

  render() {
    return (
      <div className="container post-entry">
        {this.state.product ? this.renderProduct() : this.renderEmpty()}
      </div>
    );
  }





}

export default Product;

3 个答案:

答案 0 :(得分:2)

您可以执行以下操作来实现此目的。但是React JS建议的更干净的解决方案是使用React Context API。

Am共享了React JS文档中的链接,这些链接完全具有您要解决的相同情况。

https://reactjs.org/docs/context.html#updating-context-from-a-nested-component

另外,由于您使用的是React纯组件函数,因此我们可以使用React钩子,因此您可以在

中查看

https://reactjs.org/docs/hooks-reference.html#usestate

所以在您的代码中应该是这样

./Total-Context.js

export const TotalContext = React.createContext({
  total: 0,
  setTotal: () => {

  },
});

./index.jsx

import { TotalContext } from './Total-Context';

const App = () => {
  const [total, setTotal] = useState(0);

  return (
    <TotalContext.Provider value={{total, setTotal}}>
      <div id="page-inner">
        <Header currentTotal={total} />
        <main id="content">
          <Switch>
            <Route
              exact
              path={`${Settings.path}products/:product`}
              component={Product}
            />
          </Switch>
        </main>
        <Footer />
      </div>
    </TotalContext.Provider>
  );
};

现在我们可以在Product组件中使用TotalContext使用者,并调用该方法在全局上下文中设置total方法,就像这样。

./Product.jsx

import { TotalContext } from './Total-Context';

const Product = () => (
<TotalContext.Consumer>
      {({total, setTotal}) => (
        <button
          onClick={() => {setTotal(newTotal)}}
          >
          Update total
        </button>
      )}
</TotalContext.Consumer>
)

因此,在调用click方法之后,Header组件应该具有总计的更新值。

答案 1 :(得分:0)

您可以使用redux来管理多个组件之间的状态。

getting started with redux

答案 2 :(得分:0)

要回答此问题: 由于状态是组件专有的,因此无法借助它在两个React组件之间传递状态。 道具可以在这方面帮助您。道具也不能从孩子传递给父母,它总是可以从父母传递给孩子。 您可以借助帮助实现这一点,请遵循以下文章部分:“如何将道具从子组件传递到父组件?”要对此有个清楚的主意: 网址:https://www.robinwieruch.de/react-pass-props-to-component/