Function sent as props being called continuously – React.js

I am making a newsapp i want it to have different categories, instead of using react-router-dom for navigation what i want to do is create a state object and create a key in it named category and set current category as it’s value and i have sent that key as a props to news component where i fetch news and embed that category to the fetch URL

I have made a function to set the category and its in app.js I have sent it to navbar component as props, the issue i am facing is that i can’t select a category, because for some reason the onClick of the very last category is being called continuously and I know this because I console logged the category in setCategory function, can anyone tell me why this is happening

code in app.js:

import './App.css';
import React, { Component } from 'react'
import Navbar from './components/Navbar';
import News from './components/News';

export default class App extends Component {
  constructor() {
    super()
    this.state = {
      darkMode: "light",
      country: "us",
      category: "general",
      key: "general"
    }
  }

  setCategory = (cat)=> {
    this.setState({
      category: cat
    })
    console.log(this.state.category)
  }

  setCountry = (cntry)=> {
    this.setState({
      category: cntry
    })
  }

  setDarkMode = () => {
    if (this.state.darkMode === "light") {
      this.setState({ darkMode: "dark" })
      document.body.style.backgroundColor = "black"
    } else {
      this.setState({ darkMode: "light" })
      document.body.style.backgroundColor = "white"
    }
  }

  render() {
    return (
      <div>
        <Navbar setCategory={this.setCategory} setCountry={this.setCountry} setDarkMode={this.setDarkMode} darkMode={this.state.darkMode} />
        <News key={this.state.category} category={this.state.category} country={this.state.country} pageSize={18} darkMode={this.state.darkMode} />
      </div>
    )
  }
}

code in Navbar component:

import React, { Component } from 'react'



export default class Navbar extends Component {
    constructor(props) {
        super(props)
        this.setCategory = this.props.setCategory
    }
    render() {
        return (
            <div>
                <nav className={`navbar navbar-expand-lg navbar-${this.props.darkMode} bg-${this.props.darkMode}`}>
                    <a className="navbar-brand" href="/">NewsMonkey</a>
                    <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                        <span className="navbar-toggler-icon"></span>
                    </button>

                    <div className="collapse navbar-collapse" id="navbarSupportedContent">
                        <ul className="navbar-nav mr-auto">
                            <li className="nav-item active">
                                <a className="nav-link" href="/">Home <span className="sr-only">(current)</span></a>
                            </li>
                            <li className="nav-item">
                                <a className="nav-link" href="/about">About</a>
                            </li>
                            <li className="nav-item dropdown">
                                <a className="nav-link dropdown-toggle" href="/" role="button" data-toggle="dropdown" aria-expanded="false">
                                    Categories
                                </a>
                                <div className="dropdown-menu">
                                    <p className="dropdown-item cursor-pointer" onClick={this.setCategory("business")}>Business</p>
                                    <p className="dropdown-item cursor-pointer" onClick={this.setCategory("science")}>Science</p>
                                    <p className="dropdown-item cursor-pointer" onClick={this.setCategory("technology")}>Technology</p>
                                    <p className="dropdown-item cursor-pointer" onClick={this.setCategory("entertainment")}>Entertainment</p>
                                    <p className="dropdown-item cursor-pointer" onClick={this.setCategory("health")}>Health</p>
                                    <p className="dropdown-item cursor-pointer" onClick={this.setCategory("sports")}>Sports</p>
                                    <div className="dropdown-divider"></div>
                                    <p className="dropdown-item cursor-pointer" onClick={this.setCategory("general")}>General</p>
                                </div>
                            </li>
                        </ul>
                        {/* <form className="form-inline my-2 my-lg-0">
                            <input className="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" />
                            <button className="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
                        </form> */}
                        <div className={`custom-control custom-switch text-${this.props.darkMode === "light" ? "dark" : "light"}`}>
                            <input type="checkbox" className="custom-control-input" onClick={this.props.setDarkMode} id="customSwitch1" />
                            <label className={`custom-control-label`} htmlFor="customSwitch1">Dark mode</label>
                        </div>
                    </div>
                </nav>
            </div>
        )
    }
}

>Solution :

This doesn’t do what you think it does:

onClick={this.setCategory("business")}

This calls the setCategory function immediately and uses the result of that function as the onClick handler. Don’t pass the result of calling a function to onClick, pass a function itself:

onClick={() => this.setCategory("business")}

Leave a Reply