Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React - toggle in stateless component

I am trying to toggle visiblity of a div in a stateless component like this:

    const playerInfo = (props) => {
      let isPanelOpen = false;
      return (
          <div onClick={() => isPanelOpen = !isPanelOpen }>Toggle</div>
          {isPanelOpen && <div className="info-panel">
            {props.children}
          </div>}
      );
    };

I see that the value of isPanelOpen changes to true, but the panel is not being shown. I assume that is because this is the stateless function that doesn't get called again, so once we return the jsx it will have the value of false, and won't update it later. Is there a way of fixing this, and avoiding of pasing this single variable as props through 4 more parent stateless components?

like image 533
Leff Avatar asked Mar 19 '18 16:03

Leff


People also ask

Can stateless components have functions?

Stateless components are those components which don't have any state at all, which means you can't use this. setState inside these components. It is like a normal function with no render method. It has no lifecycle, so it is not possible to use lifecycle methods such as componentDidMount and other hooks.

Can a stateless component have props?

A component can be stateless and only use the props values passed to it. These values can either contain references to a calling component's state values or references to a calling component's method. props containing a method can invoke that method from the calling component.


1 Answers

You can't tell React to re-render the UI by assigning new value directly to the variable (in your case you did isPanelOpen = !isPanelOpen).
The correct method is to use setState.

But you cannot do it in a stateless component, you must do it in a stateful component, so your code should looks like this

import React, {Component} from 'react';
class playerInfo extends Component {
    constructor(props){
        super(props);
        this.state = {
            isPanelOpen: false
        }
    }
    render() {
        return (
            <div onClick={() => this.setState({isPanelOpen: !this.state.isPanelOpen})}>Toggle</div>
            {this.state.isPanelOpen && <div className="info-panel">
              {this.props.children}
          </div>}
        );
    }
}

Explanation

Remember two things:
1) Your UI should only bind to this.state.XXXX (for stateful component) or props.XXX (for stateless component).
2) The only way to update UI is by calling setState() method, no other way will trigger React to re-render the UI.

But... how do I update stateless component since it doesn't have the setState method?

ONE ANSWER:The stateless component should be contained in another stateful component.

Example

Let's say your stateless component is called Kid, and you have another stateful component called Mum.

import React, {Component} from 'react';
class Mum extends Component {
    constructor(props){
        super(props);
        this.state = {
            isHappy: false
        }
    }
    render() {
        return (
           <div>
                <button onClick={() => this.setState({isHappy: true})}>Eat</button>
                <Kid isHappy={this.state.isHappy}/>
           </div>
        );
    }
}

const Kid = (props) => (props.isHappy ? <span>I'm happy</span> : <span>I'm sad</span>);
like image 59
Wong Jia Hau Avatar answered Sep 19 '22 11:09

Wong Jia Hau