最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Button onClick triggered when init in React application - Stack Overflow

programmeradmin1浏览0评论

I'm trying to make a simple dropdown menu but I have some problems with onClick event on list items which are in child component, the 'handleClick' function is suppose to trigger when click on a list item, but the function is trigged twice when page loaded (because there are two lists here), and when I click on list again, it will trigger twice again, I'm sure it's a simple question but I passed few hours on it but I don't really understand what it happen here, hope someone can help me please, thx!

here is my code:

import React from 'react';
import Dropdown from './../elements/dropdown.js!jsx';

export class TestPage extends React.Component {

  constructor() {
    super();
    this.noteLIst = [
      {name: 'note', label: 'Note global'},
      {name: 'digitalCulture', label: 'Digital Culture'}
    ];
  }

  handleItemClick(company) {
    console.log(company);
  }

  render() {
    return (
      <div className="widget">
        <Dropdown list={this.noteLIst} selected={this.noteLIst[0]} whenItemClicked={this.handleItemClick} />
      </div>
    );
  }
}

Dropdown.js

import React from 'react';

export class Dropdown extends React.Component {

  constructor() {
    super();
    this.state = {
      listVisible: false
    };
  }

  showMenu() {
    this.setState({
      listVisible: true
    });
    document.addEventListener("click", this.hide);
  }

  hide() {
    this.setState({
      listVisible: false
    });
    document.removeEventListener("click", this.hide);
  }

  handleClick(item) {
    console.log(item); // Here will log 2 items
    this.props.whenItemClicked(item);
  }

  render() {
    let listItems = _.map(this.props.list, (list, index) => {
      return (
        <li key={index} className={list} onClick={this.handleClick(list)}>{list.name}</li>
      );
    });

    return (
      <div className = {"dropdown-container" + (this.state.listVisible ? " show" : "")}>
        <div className = {"dropdown-display" + (this.state.listVisible ? " clicked" : "")} onClick = {this.show}>
          <span>
            <img className="icon-arrow-bottom" src="build/image/arrow_bottom_black.png" />
          </span>
          <span>
            {this.props.selected.name}
          </span>
        </div>
        <ul className="dropdown-list" >
          {listItems}
        </ul>
      </div>
    );
  }
}

I'm trying to make a simple dropdown menu but I have some problems with onClick event on list items which are in child component, the 'handleClick' function is suppose to trigger when click on a list item, but the function is trigged twice when page loaded (because there are two lists here), and when I click on list again, it will trigger twice again, I'm sure it's a simple question but I passed few hours on it but I don't really understand what it happen here, hope someone can help me please, thx!

here is my code:

import React from 'react';
import Dropdown from './../elements/dropdown.js!jsx';

export class TestPage extends React.Component {

  constructor() {
    super();
    this.noteLIst = [
      {name: 'note', label: 'Note global'},
      {name: 'digitalCulture', label: 'Digital Culture'}
    ];
  }

  handleItemClick(company) {
    console.log(company);
  }

  render() {
    return (
      <div className="widget">
        <Dropdown list={this.noteLIst} selected={this.noteLIst[0]} whenItemClicked={this.handleItemClick} />
      </div>
    );
  }
}

Dropdown.js

import React from 'react';

export class Dropdown extends React.Component {

  constructor() {
    super();
    this.state = {
      listVisible: false
    };
  }

  showMenu() {
    this.setState({
      listVisible: true
    });
    document.addEventListener("click", this.hide);
  }

  hide() {
    this.setState({
      listVisible: false
    });
    document.removeEventListener("click", this.hide);
  }

  handleClick(item) {
    console.log(item); // Here will log 2 items
    this.props.whenItemClicked(item);
  }

  render() {
    let listItems = _.map(this.props.list, (list, index) => {
      return (
        <li key={index} className={list} onClick={this.handleClick(list)}>{list.name}</li>
      );
    });

    return (
      <div className = {"dropdown-container" + (this.state.listVisible ? " show" : "")}>
        <div className = {"dropdown-display" + (this.state.listVisible ? " clicked" : "")} onClick = {this.show}>
          <span>
            <img className="icon-arrow-bottom" src="build/image/arrow_bottom_black.png" />
          </span>
          <span>
            {this.props.selected.name}
          </span>
        </div>
        <ul className="dropdown-list" >
          {listItems}
        </ul>
      </div>
    );
  }
}
Share Improve this question asked Oct 4, 2015 at 19:14 Tachun LinTachun Lin 9723 gold badges11 silver badges18 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 12

When you use the onClick event and you want to pass parameters to the handler method, you have to use the function bind. Thus, the handler will be triggered only when you click on the list item.

onClick={this.handleClick.bind(this, list)}

This would be your Dropdown.js:

import React from 'react';

export class Dropdown extends React.Component {

  constructor() {
    super();
    this.state = {
      listVisible: false
    };
  }

  showMenu() {
    this.setState({
      listVisible: true
    });
    document.addEventListener("click", this.hide);
  }

  hide() {
    this.setState({
      listVisible: false
    });
    document.removeEventListener("click", this.hide);
  }

  handleClick(item) {
    console.log(item); // it will be log 1 item when you click
    this.props.whenItemClicked(item);
  }

  render() {
    let listItems = _.map(this.props.list, (list, index) => {
      return (
        <li key={index} className={list} onClick={this.handleClick.bind(this, list)}>{list.name}</li>
      );
    });

    return (
      <div className = {"dropdown-container" + (this.state.listVisible ? " show" : "")}>
        <div className = {"dropdown-display" + (this.state.listVisible ? " clicked" : "")} onClick = {this.show}>
          <span>
            <img className="icon-arrow-bottom" src="build/image/arrow_bottom_black.png" />
          </span>
          <span>
            {this.props.selected.name}
          </span>
        </div>
        <ul className="dropdown-list" >
          {listItems}
        </ul>
      </div>
    );
  }
}

It should be noted that this works even when the function does not belong to this! Example:

config/GetFireBaseConfigFromEnv.ts

import dotenv from "dotenv";
import path from "path";
import { FirebaseOptions } from "firebase/app";

const GetFireBaseConfigFromEnv = (): => {
  dotenv.config({path: path.resolve(__dirname, "../.env.development")});

  const config: FirebaseOptions = {
      apiKey: process.env.API_KEY,
      appId: process.env.APP_ID,
      authDomain: process.env.AUTH_DOMAIN,
      measurementId: process.env.MEASUREMENT_ID,
      messagingSenderId: process.env.MESSAGING_SENDER_ID,
      projectId: process.env.PROJECT_ID,
      storageBucket: process.env.STORAGE_BUCKET
  };

  return config;
}

export default GetFireBaseConfigFromEnv;

auth/SignInWithGoogle.ts

import { GoogleAuthProvider, Auth, signInWithPopup } from "firebase/auth";

const SignInWithGoogle = (auth: Auth): void => {
  const provider: GoogleAuthProvider = new GoogleAuthProvider(auth);
  signInWithPopup(auth, provider);
}

export default SignInWithGoogle;

components/app.ts

import React, { JSX } from "react";
import GetFireBaseConfigFromEnv from "config/GetFireBaseConfigFromEnv";
import SignInWithGoogle from "auth/SignInWithGoogle";

const App: React.FC = (): JSX.Element => {
  return (
    <>
      <div>
        <h1>App</h1>
        <button onClick={SignInWithGoogle.bind(this, GetFireBaseConfigFromEnv())}
          value="Login with Google"/>
      </div>
    </>
  );
}

To work it out easily with functional components, since the class components became almost deprecated as of React v16, call the handler function from the body of an arrow function. I called the handler function (handleSearch) from inside a new arrow function because my handler function was an async function which returns a result so it was being called on every component render rather than on click event.

    <button style={{height:'55px'}} onClick={ () => {
          handleSearch(search, fetchData, exerciseOptions, setSearch, setSearchedExercises, setShowHeaderTitle, setBodyPart)}}>
            Search
</button>
发布评论

评论列表(0)

  1. 暂无评论