How to pass values between components in React JS?

2019-08-29 13:17发布

So I've been stuck on this assignment for about a week now on this one part. I've asked a question about it here but due to my inexperience with React I still can't figure out how to solve it. The assignment is as follows:

The goal of this project is to create an application that simulates the operation of a cafe. You will need to create components for the customer, barista, and coffee machine.

Customer component

This is the "User facing" component. Here you should have 3 option items that will cause this component to fire a custom event. These options are: Drip brew, french press, and espresso.

When one of the objects is clicked, it should highlight and stay highlighted until another is clicked.

Barista Component

This component takes the orders, and displays a response on the DOM, formatted as such:

"One {{ order_type }}? That will be {{ order_value }}."

When taking a new order, play an animation to transition out the next text, and transition in new text.

After a delay of five seconds (use the setTimeout method), fire an event to start the preparation of the coffee. Change the text in this component to read, "Waiting for {{ order_type}}"

This component also needs a method that will be called when the machine finishes it preparation. This "coffeeFinished" method should display a message like so: "Here is you {{ order_type }}, enjoy!".

When taking a new order, play an animation to transition out the next text, and transition in new text.

Machine Component

This component, when its "brewCoffee" method is called, should display a message visually to the user that says "Currently brewing: {{ order_type }}".

Again, using setTimeout, have this component wait five seconds before firing a "brewingComplete" event. When this event is fired, also change this component's output to "{{ order_type }} is done."

While the coffee is brewing, a loading bar needs to be animated to display how much time until the process is over.

The Application Object

The application object will be responsible for listening for each of the events fired from your components, and calling the appropriate methods on the next in line. For instance, when the Machine Component fires the event "brewingComplete", the application should respond to the event by calling the deliver order method on the Barista component.

Additionally, this component should store the current order name in its properties. This is the variable that should be referenced when displaying the order being brewed and repeated by the barista.

The problem I've been having is taking one component, in this case when a user pushes a button, and using those values in the other components with the timeout function. What I have so far is:

App.js

import React, { Component } from 'react';
import './App.css';
import './Customer.js';
import Customer from './Customer.js';
import './Barista.js';
import Barista from './Barista.js';
import './CoffeeMachine.js';
import CoffeeMachine from './CoffeeMachine.js';

class App extends Component {

  //The State with all the stuff that gets updated along the way
  state = {
    coffee: "",
      value: 0,
      bgColor: 'transparent'
  }


  //I apparently can't comment in the render thing without it appearing on the page. So, the Green box for the Customer Component, the Orange box for the Barista Component, and the Blue Box for the Machine component.
  render() {

    return (
      <div className="App">

          <div className="row" id="green">

          <Customer order = {(coffeeSelect, value) => {this.send(coffeeSelect, value)}}/>
          </div>


          <div className="row" id="orange">
          <Barista coffeeSelect = { this.state.coffee } value = { this.state.value }/>
          </div>


          <div className="row" id="blue">
          <CoffeeMachine coffeeSelect = { this.state.coffee } value = { this.state.value }/>
          </div>
      </div>
    )
  }

  //Sends the selected values to the other components
  send(coffeeSelect, value) {
    this.setState({coffee: coffeeSelect, value: value});
  }



}

export default App;

Customer.js

import React, { Component } from 'react';
import './Customer.css';

class Customer extends Component {


//Each button has a div to be highlighted upon being selected
    render() {

        return(
            <div>

            <div className="button">
            <button onClick={() => { this.optionSelect("Drip")}}>
        Drip
        </button>
        </div>

        <div className="button">
        <button onClick={() => { this.optionSelect("French Press")}}>
        French Press
        </button>
        </div>

            <div className="button">
        <button onClick={() => { this.optionSelect("Espresso")}}>
        Espresso
        </button>


            </div>

        </div>);
    }


    //Receives the brew, and assigns it to its matching cost
    optionSelect(userChoice) {
        var coffeeSelect = userChoice;
        var value = 0;

        if (coffeeSelect === "Drip"){
            value = 5;
        } else if (coffeeSelect === "French Press"){
            value = 6;
        } else if (coffeeSelect === "Espresso"){
            value = 3;
        }

        this.props.order(coffeeSelect, value);
        console.log(coffeeSelect);
        console.log(value);



    }



}

export default Customer;

Barista.js

import React, { Component } from 'react';

class Barista extends Component {

    //The default text in the Barista Component until the user sends it the coffee and cost
    state = {
        text: "Hello, How May I Help You Today?",
        orderText: "One " + this.props.coffee + "? That will be $" + this.props.value
    }

    //This is where I've hit the brick wall. I just need to get the buttons to also call this thing but everything I've looked up just gives me errors. If I could figure out where to call this I can do the timer to "prep" the coffee.
    confirm(){
        this.setState({ text: "One " + this.props.coffee + "? That will be $" + this.props.value});
        setTimeout(() => {this.waiting()}, 5000);
    }

    waiting() {
        this.setState({ text:"Waiting for " + this.props.coffee});
        setTimeout(() => {this.finish()}, 5000);
    }

    finish() {
        this.setState({ text: "Here is your " + this.props.coffee + ". Enjoy!"});
    }


    render() {

        return(

            <div>

            {this.state.text}



                </div>
        )

    }


}

export default Barista;

As by this point I am completely stuck, I don't have anything for the machine component yet. While I have no doubt that I have a multitude of problems here, my main problem is when a user presses a button in the customer component how to change the text in the barista component. Is there something simple I am missing or am I completely off the mark?

2条回答
走好不送
2楼-- · 2019-08-29 13:47

You're falling victim to the most classic of all React problems. Instead of reacting to state changes, you are only rendering the view based on an initial state.

This super simple change will fix your problem:

// Barista.js

....

render() {
  return (
    <div>
      {"One " + this.props.coffee + "? That will be $" + this.props.value}
    </div>
  )
}
....

Now when your parent state changes from clicking the button in Customer the Barista render method will show the updated message because this.props.value has changed.

Note: your props aren't named correctly.. in App you called it coffeeSelect:

<Barista coffeeSelect=

.. but in Barista you called it this.props.coffee so make sure to name your props the same. In App it should be:

<Barista coffee=
查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-08-29 14:00

EDIT: Fixed the problem with having to press the button twice.

    import React, { Component } from 'react';

    class Barista extends Component {

    //The default text in the Barista Component until the user sends it the coffee and cost
    state = {
        text: "Hello, How May I Help You Today?"

    }

    //The domino effect of messages. Upon being sent the brew and value variables, the confirm function is called which calls the waiting function which calls the finish function.
    confirm(){
        this.setState({ text: "One " + this.props.coffee + "? That will be $" + this.props.value});
        setTimeout(() => {this.waiting()}, 5000);
    }

    waiting() {
        this.setState({ text:"Waiting for " + this.props.coffee});
        setTimeout(() => {this.finish()}, 1000);
    }

    finish() {
        this.setState({ text: "Here is your " + this.props.coffee + ". Enjoy!"});
    }

    componentWillUpdate(nextProps,nextState) {
        if (this.props.coffee !== null && this.state === nextState) {
            setTimeout(() => {this.confirm()}, 3000);
        }
    }

    render() {

console.log(this.props.coffee);

        return(

            <div>

            {this.state.text}

    </div>
    )
    }
}

export default Barista;
查看更多
登录 后发表回答