2

I recently have begun learning reactjs and I am having a hard time comprehending state and how it's used. I have built two stateless components (boxOne and boxTwo) and I have a property "Move Me" that I would like to pass between the two components on the click of a button (MoveButton). Below is the code to where I reached to before getting stuck

   class MoveButton extends React.Component {
        render() {
            return (
                    <button className="thebutton">
                        Click To Move
                    </button>
            );
        }
    }
    class BoxOne extends React.Component {
        render() {
            return (
                    <div className="boxOne-container">
                        {this.props.name}
                    </div>
            );
        }
    }
    class BoxTwo extends React.Component {
        render() {
            return (
                    <div className="boxTwo-container">
                    </div>
            );
        }
    }
    function App() {
        return (
                <div>
                    <BoxOne name="Move Me" />
                    <BoxTwo />
                    <MoveButton />
                </div>
        );
    }
    ReactDOM.render(<App />,document.getElementById('container'));
6
  • is the name with value "move me" just being alternated between each box when the move button is toggled? Commented Jun 28, 2017 at 17:48
  • What exactly do you want to happen when the move button is clicked? Like from the user's perspective (the only perspective that really matters). Commented Jun 28, 2017 at 17:49
  • @MiguelMota Yes, the value "move me" would just be alternated between each box when the button is toggled. So it would go from BoxOne to BoxTwo Commented Jun 28, 2017 at 18:06
  • @AdamLeBlanc So the "Move Me" value would start in box One, and when the user clicks the button, it alternate to Box Two, and once they would click the button again it would alternate to box One Commented Jun 28, 2017 at 18:07
  • Okay, I gottcha bud. Give me a second. Making a codepen to go along with the answer. Commented Jun 28, 2017 at 18:18

2 Answers 2

1

Okay, so here is a codepen with everything working.

Here is the code for future generation in the event codepen dies before S-O (I think you can run it here as well??).

class Box extends React.Component {
  render(){
    return (
      <div>
          {this.props.name ? this.props.name : "nothing"}
      </div>
    );
  }
}

class MoveButton extends React.Component {
  render(){
    return(
      <button onClick={this.props.on_click_handler}>
        Click Me
      </button>
    );
  }
}

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      first_button: true
    };
    this.on_click_handler = this.on_click_handler.bind(this);
  }
  on_click_handler(){
    this.setState({
      first_button: !this.state["first_button"]
    });
  }
  render() {
    return (
      <div> 
        <Box name={this.state["first_button"] ? "Move Me": null} />
        <Box name={!this.state["first_button"] ? "Move Me": null} />
        <MoveButton on_click_handler={this.on_click_handler} />
      </div>      
    );
  }
}

ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

So, anyways... here's the explanation.

Basically what you want to do is have the higher level component deal with the state. In this case, we're talking about App. Eventually you'll start to learn where state should go, but generally you want it to be at the highest point that makes sense. Basically, in this case since the App component has the thing (the button) that is changing the state of the two Box we want the state there.

I make the actual function that deals with the click inside the App component, and pass it down to the sub component, MoveButton. I do this because the function is changing state in the App component, so it has to be there. I also had to bind the this in the constructor, which is this line: this.on_click_handler = this.on_click_handler.bind(this);. This just makes sure that this is always referencing the correct thing inside that function.

Then in that handler function I change the components state, which causes a re-render. I use the ternary operator to see which instance of Box I should be passing the "Move me" to. I also use the ternary operator in Box itself to either put the name, or "nothing" but you can change that whatever.

Hope that helps.

P.S: You don't need two different component classes for Box. They're the same thing, so just reuse the same component, but make two instances of it. Which is what I did here.

Sign up to request clarification or add additional context in comments.

4 Comments

Also, you can change all of these (except App) into stateless components. I just quickly did it up and made them full classes without putting a lot of thought.
Thanks man!! This really helped with my learning, especially the walk-through you provided. Just out of curiosity, what would be an approach (you don't have to go into detail if it takes too long) if I didn't want anything to appear in the second box component(i.e where it says "nothing"?) I played around with some changes off the top of my head and I noticed it started altering the position of the boxes instead of the "Move Me". Again, appreciate the time and help!
just replace it with null
Here is another codepen with that. I also added some CSS to make it easier to see.
0

First off I'd strongly suggest to read the entire react documentation: https://facebook.github.io/react/docs/hello-world.html (or at the very least, to start off the whole quick start section, which covers all the basic you need). It covers pretty much all of react (React has quiet a small scope!).

You need to have some kind of state. Currently your class components (MoveButton, BoxOne and BoxTwo) have access to state but don't use it. Your App component defined as function does not have access to any kind of own state.

Your state needs to be in a common parent component, which you can then pass down to child components as props. The child components may be stateless. In your case that would be the App Component, which you could use a class for instead to make react state available, while the other three components you could rewrite to be stateless functions.

Now I don't understand what exactly you want to happen, I'll just assume you want to move the "Move me" text from one Box to the other on clicking the button. Therefore both boxes have the ability to display text, controlled by the parent. Both boxes could have a react prop called 'name', received by the parent (App). The button itself needs to emit an event (callback), defined in the parent and passed down to the button as prop. I'll call that prop 'handleEvent'.

The implementation could look like such:

import React, {Component} from 'react';
import ReactDOM from 'react-dom';

function BoxOne(props) {
    return (
        <div>BoxOne: {props.name}</div>
    );
}

function BoxTwo(props) {
    return (
        <div>BoxTwo: {props.name}</div>
    );
}

function MoveButton(props) {
    return (
        <button onClick={props.handleEvent}>Click to Move</button>
    );
}

class App extends Component {
    constructor(props) {
        super(props);

        this.state = {
            boxOneName: 'Move me',
            boxTwoName: ''
        };

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

    handleEvent() {
        this.setState({
            boxOneName: this.state.boxTwoName,
            boxTwoName: this.state.boxOneName
        });
    }

    render() {
        return (
            <div>
                <BoxOne name={this.state.boxOneName}/>
                <BoxTwo name={this.state.boxTwoName}/>
                <MoveButton handleEvent={this.handleEvent}/>
            </div>
        );
    }
}

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

Everything used in the example is adressed within the react quick start guide.

Let me know if anything is still unclear :)!

3 Comments

This isn't a great solution, because you're making an extra component class, without reason to do so. Would be much better to reuse the same class.
I sticked to your own example as close as possible for simplicities sake. Of course you can use the same Box component: <BoxOne name={this.state.boxOneName}/> <BoxOne name={this.state.boxTwoName}/> And delete BoxTwo entirely.
@Milant Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.