Search code examples
javascriptreactjsfunction-call

I am trying to call the switch_func function. But somehow not able to get the desired result


<!DOCTYPE html>
<html>
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/[email protected]/babel.min.js"></script>
<body>
  
<div id="root"></div>

<script type="text/babel">
class Hello extends React.Component {
  constructor(props) {
        super(props);
        this.state = { myStr: "Initial state" };
        this.switch_func = this.switch_func.bind(this);
    }
    
    switch_func = () => {
  // the setState if commented ...the initial state of myStr is executed ..meaning the function is called however the setState method doesnt work . Can anyone tell why this is happening?
  
    	this.setState({ myStr: "yess"});
      return (
            <div>
                <h3>{this.state.myStr}</h3>
            </div>
        );
    }
    

    render() {
        return (
            <div>
                <h1>Hello, world!</h1>
				{this.switch_func()}
            </div>
        );
    }
}

ReactDOM.render(<Hello />, document.getElementById('root'))
</script>

</body>
</html>

Even after binding the function switch_func, it is not executed and the state of myStr remains the same that was initialized. Please help with where the coding is failing to not show desired result.

Can anyone tell why the setState method isnt working here?

Desired output is that the myStr's state is changed to - "Yes its four!"

class MyClass extends React.Component {
    constructor(props) {
        super(props);
        this.state = {myStr: "Initial state"};
        this.switch_func = this.switch_func.bind(this);
    }
    switch_func = ()=> {
        this.setState({myStr: "In function"});
        switch (1 + 3) {
            case 2 + 2:
                this.setState({ myStr: "Yes its four!"});
                break;
            default:
                this.setState({ myStr: "Oops! default"});
        }

    return(
        <div>
            <h3>{this.state.myStr}</h3>
        </div>
    );
  }

    render(){
        return (
            <div>
            <h1>Hello, world!</h1>
            {this.switch_func()}
        </div>
        );
    }
}

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



Solution

  • You should not call the switch function inside render, as it may cause your component to land in an infinite loop - every time it's rendered, state changes so... It's rendered again.

    Also, it's highly dangerous to mix rendering and state updating in one function - it should never be done, as it may cause a lot of optimization leaks.

    Move your function call to another method, e.g. componentDidMount():

    class MyClass extends React.Component {
        constructor(props) {
            super(props);
            this.state = {myStr: "Initial state"};
        }
    
        componentDidMount() {
          switchFunc();
        }
    
        switchFunc = () => {
            switch (1 + 3) {
                case 2 + 2:
                    this.setState({ myStr: "Yes its four!"});
                    break;
                default:
                    this.setState({ myStr: "Oops! default"});
            }
        }
    
        render(){
            return (
                <div>
                    <h1>Hello, world!</h1>
                    <div>
                        <h3>{this.state.myStr}</h3>
                    </div>
                </div>
            );
        }
    }
    
    ReactDOM.render(
      <MyClass />,
      document.getElementById('root')
    );
    

    componentDidMount is a special method (as render) that is supplied by React and allows for controlling your component behavor when the component is mounted. More on that methods here: https://reactjs.org/docs/state-and-lifecycle.html

    Also, note that separating rendering myStr from the render method is an overkill for the time being - just use it directly in render method as in my example.

    Just a side note - try to use camelCased names for your methods, to keep them consistent with the rest of the code (as in my updated example).

    Another optimization info on binding - you added .bind() call to your constructor - it's not needed, as your switchFunc is not used in any context outside of the class (hence, its this always points to the class, so you don't need to .bind() the context again). Also, what's more important - you wrote it as a lambda (() => {}) function, not a normal function - lambdas don't have their context and inherit parent context from where they are defined - hence it will always point to class this context without any explicit binding