简体   繁体   中英

React: onClick on div jumps to top of page instead of executing callback function

I have this React application that serves as an inventory system. I have this page where there exists a plus and minus button that allows the user to increase or decrease the stock number for an individual item (it's pretty much a counter). So what's happening is that at first decreasing/increasing the counters for individual products were working but as my number of products, it just stopped working. When I tried to increase/decrease product, it would just jump to the top of the page. After analysis, I found that I could increase/decrease stock numbers for products that were already on the page when first accessed (aka I don't need to scroll down to view them). The ones that were not working were the ones that required some scrolling down to see them.

Here is the component (IncreaseStockItem) that renders the product name along with the plus and minus button

import React, { Component } from "react";

class IncreaseStockItem extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inStock: props.product.inStock,
      name: props.product.name,
      barcode: props.product.barcode,
    };
  }

  onProductIncrease = (e) => {
    e.preventDefault();
    var updatedNumber = this.state.inStock + 1;
    this.setState({ inStock: updatedNumber }, function () {
      this.handleAfterChange();
    });
  };

  onProductDecrease = (e) => {
    e.preventDefault();
    var updatedNumber = this.state.inStock - 1;
    this.setState({ inStock: updatedNumber }, function () {
      this.handleAfterChange();
    });
  };

  handleAfterChange = () => {
    this.props.onInputChange(this.state);
  };

  
  render() {
    return (
      <div className="columns">
        <div className="column is-two-thirds ml-4">
          <div className="field">
            <input className="input" value={this.state.name} readOnly></input>
          </div>
        </div>
        <div className="column">
          <span className="field">
            <div onClick={this.onProductDecrease} className="button is-danger">
              <i className="fa fa-minus"></i>
            </div>

            <input
              value={this.state.inStock}
              className="input mx-5 has-text-centered"
              type="text"
              style={{ width: "45px" }}
              readOnly
            ></input>
          </span>
          <div onClick={this.onProductIncrease} className="button is-success">
            <i className="fa fa-plus"></i>
          </div>
        </div>
      </div>
    );
  }
}

export default IncreaseStockItem;

Here is the component that renders the list of items:

import React from "react";
import IncreaseStockItem from "./IncreaseStockItem";

const IncreaseStockProductList = ({ products, onInputChange }) => {
  const renderedList = products.map((product) => {
    return (
      <IncreaseStockItem
        key={product._id}
        product={product}
        onInputChange = {onInputChange}
      />
    );
  });

  return renderedList;
};

export default IncreaseStockProductList;

The component looks like this: Component

I have tried my best to describe the problem and it still might be unclear. Let me know if you need more clarifications.

Note: The same problem happens when I use react-router Link with a link tag that's out of context.

EDIT 1:

Whenever I zoom out so that all components are within the context of the screen (aka no need of scrolling down), everything works fine.

EDIT 2:

The component hierarchy goes like this:

IncreaseStock -> IncreaseStockProductList -> IncreaseStockItem

Code for IncreaseStock below:

import React, { Component } from "react";
import axios from "axios";
import { withRouter } from "react-router-dom";
import Button from "./Button";
import IncreaseStockProductList from "./IncreaseStockProductList";
import Message from "./Message";
import SearchBar from "./SearchBar";

class IncreaseStock extends Component {
  constructor(props) {
    super(props);
    this.state = { products: [], updatedProducts: [] };
  }

  routingFunction = () => {
    var title = "Mises à jour du nombre de produits";
    var message =
      "Le nombre d'articles des produits suivants a été mis à jour:";

    this.props.history.push({
      pathname: "/products/",
      state: {
        title: title,
        message: message,
        products: this.state.updatedProducts,
      },
    });
  };

  onSearchBarChange = async (target) => {
    var barcode = target.value;
    axios.get("/api/products/barcode/" + barcode).then((response) => {
      if (response.data !== null) {
        this.props.history.push({
          pathname: "/products/" + barcode,
        });
      }
    });
  };

  componentDidMount() {
    axios.get("/api/products").then((response) => {
      this.setState({ products: response.data });
    });
  }

  // https://stackoverflow.com/questions/37435334/correct-way-to-push-into-state-array
  onInputChange = (data) => {
    var tempData = {
      inStock: data.inStock,
      barcode: data.barcode,
      name: data.name,
    };
    var tempArray = this.state.updatedProducts.slice();
    tempArray = tempArray.filter(function (obj) {
      return obj.barcode !== data.barcode;
    });
    tempArray.push(tempData);
    this.setState({ updatedProducts: tempArray });
  };

  onFormSubmit = (event) => {
    event.preventDefault();
    var payload = this.state.updatedProducts;
    axios({
      method: "post",
      url: "/api/products/increase",
      data: payload,
    }).then((response) => {
      this.routingFunction();
    });
  };

  render() {
    return (
      <div className="section">
        <div className="container">
          <h1 className="title has-text-centered is-size-4 mb-3">
            Modifier Votre Stock
          </h1>
          <div className="columns">
            <div className="column is-three-fifths is-offset-one-fifth">
              <Message
                products={[]}
                title="Instructions"
                type="info"
                message="Pour rechercher un produit scanner son barcode en &#233;tant sur cette page."
              />
              <SearchBar onSearchBarChange={this.onSearchBarChange} />

              <form onSubmit={this.onFormSubmit}>
                <div className="card mb-5">
                  <IncreaseStockProductList
                    products={this.state.products}
                    onInputChange={this.onInputChange}
                  />
                </div>
                <Button text="Confirmer" />
              </form>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default withRouter(IncreaseStock);

EDIT 3: Same problem with react-router-dom

The same problem happens when I use react-router-dom's Link component that is out of context, clicking on the link just makes the page go to the top.

I have a component page that lists all products inside of a table and I have a modify link that takes the user the edit page for a specific produt.

Below is the TableCell component that displays individual cell/product.

Image of TableCell

import React, {Component} from "react";
import { Link } from "react-router-dom";

class TableCell extends Component {
  constructor(props) {
    super(props);
    var notice = props.product.inStock === 0 ? "has-background-warning" : "";
    this.state = {notice:notice, id: props.product._id}
  }

  onDelete = (e) => {
    this.props.onDelete(this.props.product._id);
  }

  render() {
    return (
        <tr className={this.state.notice}>
        <td>{this.props.product.barcode}</td>
        <td>{this.props.product.name}</td>
        <td>{this.props.product.price}</td>
        <td>{this.props.product.inStock}</td>
        <td>
          <b>
            <Link
              to={{
                pathname: "/products/edit/" + this.props.product._id,
                product: this.props.product,
              }}
              className="button is-info"
            >
              Modifier
            </Link>
          </b>
        </td>
        <td>
          <b>
            <button onClick={this.onDelete} className="button is-danger has-text-white delete-button"><b>Supprimer</b></button>
          </b>
        </td>
      </tr>
    )
  }
}

export default TableCell;

You can try binding "this" to the function, maybe the render or the click its executed out of context, try with this:

onClick={this.onProductIncrease.bind(this)}

as tip, inquire about, execution context in javascript, and go to reacts official documentation

Is there any output in the console when you try to fire the function? Try adding a console.log in the onProductIncrease function to see if it is firing properly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM