【问题标题】:Why am I receiving 'Invalid hook call' error?为什么我会收到“无效的挂钩调用”错误?
【发布时间】:2021-10-01 22:10:43
【问题描述】:

我在单击按钮时调度 redux 操作。单击按钮时,我会收到错误“无效的挂钩调用。钩子只能在函数组件的主体内部调用。我可以在页面渲染上调度相同的操作,它工作正常。我在 onClick 上发送了其他操作,但这个操作不起作用。 这是动作

import axios from "axios";

export const addReview = (productInfo) => async (dispatch) => {

  try {
    await axios({
      method: "post",
      url: url,
      header: { "Content-Type": "application/json" },
      data: {
        name: productInfo.name,
        rating: productInfo.rating,
        description: productInfo.description,
        buyAgain: productInfo.buyAgain,
        productId: productInfo.productId,
      },
    }).then((response) => {
      dispatch({
        type: "PRODUCTS_SUCCESS",
        payload: response.data,
      });
    });
  } catch (error) {
    dispatch({
      type: "PRODUCTS_FAILURE",
      payload: error,
    });
  }
};

这是 onClick 事件的动作调度

  const submitReview = () => {
      let productInfo = {
        name,
        rating: starRate,
        description: message,
        buyAgain,
        productId: currentProduct,
      };
      dispatch(addReview(productInfo));
  };

这是整个组件

import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import "./ProductReview.css";
import { ImStarEmpty } from "react-icons/im";
import { ImStarFull } from "react-icons/im";
import { IoPersonCircle } from "react-icons/io5";
import { addReview } from "../../actions/addReview";

export const ProductReview = () => {
  const [starRate, setStarRate] = useState();
  const [message, setMessage] = useState();
  const [buyAgain, setBuyAgain] = useState(true);
  const [missingRating, setMissingRating] = useState(false);

  const dispatch = useDispatch();

  const fName = localStorage.getItem("firstName");

  const currentProduct = useSelector(
    (state) => state.userInfoReducer.currentProductReview
  );

  const allProducts = useSelector((state) => state.productReducer.data);

  let productToDisplay;
  let title;

  let name;

  allProducts.map((product) => {
    if (product._id === currentProduct) {
      productToDisplay = product;
      if (product.title.length > 60) {
        title = product.title.substring(0, 60) + "...";
      }
    }
    return productToDisplay;
  });

  const submitReview = () => {
    let productInfo = {
      name,
      rating: starRate,
      description: message,
      buyAgain,
      productId: currentProduct,
    };
    dispatch(addReview(productInfo));
  };

  return (
    <>
      <div className="product-review-container">
        <h1 className="product-review-title">Create Review</h1>
        <div className="product-review-product">
          <img
            className="review-product-img"
            src={productToDisplay.image}
            alt="product"
          />
          <h2 className="review-product-title">{title}</h2>
        </div>
        <hr className="line-break" />
        <div className="review-product-review">
          <div className="review-product-review-container">
            <h2 className="review-product-review-title">Overall Rating</h2>
            <p className="review-product-review-stars">
              {starRate >= 1 ? (
                <ImStarFull
                  className="star-full"
                  onClick={() => setStarRate(1)}
                />
              ) : (
                <ImStarEmpty
                  className="star-empty"
                  onClick={() => setStarRate(1)}
                />
              )}
              {starRate >= 2 ? (
                <ImStarFull
                  className="star-full"
                  onClick={() => setStarRate(2)}
                />
              ) : (
                <ImStarEmpty
                  className="star-empty"
                  onClick={() => setStarRate(2)}
                />
              )}
              {starRate >= 3 ? (
                <ImStarFull
                  className="star-full"
                  onClick={() => setStarRate(3)}
                />
              ) : (
                <ImStarEmpty
                  className="star-empty"
                  onClick={() => setStarRate(3)}
                />
              )}
              {starRate >= 4 ? (
                <ImStarFull
                  className="star-full"
                  onClick={() => setStarRate(4)}
                />
              ) : (
                <ImStarEmpty
                  className="star-empty"
                  onClick={() => setStarRate(4)}
                />
              )}
              {starRate >= 5 ? (
                <ImStarFull
                  className="star-full"
                  onClick={() => setStarRate(5)}
                />
              ) : (
                <ImStarEmpty
                  className="star-empty"
                  onClick={() => setStarRate(5)}
                />
              )}
            </p>
            {missingRating ? (
              <p className="missing-rating">! Must choose a rating</p>
            ) : (
              ""
            )}
          </div>
          <button
            className="review-product-review-clear"
            onClick={() => setStarRate(0)}
          >
            Clear
          </button>
        </div>
        <div className="review-product-buy-again">
          <h2 className="review-product-buy-again-title">
            Would you buy this item again?
          </h2>
          <div className="btn-group btn-group-toggle" data-toggle="buttons">
            <label className="btn btn-secondary active">
              <input
                type="radio"
                name="options"
                id="option1"
                autoComplete="off"
                onClick={() => setBuyAgain(true)}
              />{" "}
              Yes
            </label>
            <label className="btn btn-secondary">
              <input
                type="radio"
                name="options"
                id="option2"
                autoComplete="off"
                onClick={() => setBuyAgain(false)}
              />{" "}
              No
            </label>
          </div>
        </div>
        <hr className="line-break" />
        <div className="review-product-message">
          <h2 className="review-product-message-title">
            Add a written message
          </h2>
          <input
            type="text"
            className="form-control review-product-message-input"
            placeholder="What did you like or dislike?"
            onChange={(e) => setMessage(e.target.value)}
          />
          <h2 className="review-product-name-title">Choose your public name</h2>
          <p className="review-product-appear">
            This is how you'll appear to other customers
          </p>
          <div className="review-product-user-info">
            <IoPersonCircle className="review-product-profile" />
            <input
              type="text"
              className="form-control review-product-profile-name"
              defaultValue={fName}
              onChange={(e) => (name = e.target.value)}
            />
          </div>
          <hr className="line-break" />
          <button
            className="review-product-submit"
            onClick={() => submitReview()}
          >
            Submit
          </button>
          {missingRating ? (
            <p className="missing-rating">Missing information</p>
          ) : (
            ""
          )}
        </div>
      </div>
    </>
  );
};

【问题讨论】:

  • 你能发布你的整个组件吗?您拥有submitReview 功能的那个?
  • 我已经添加了整个组件。包含 onClick 事件的按钮位于组件的底部
  • 这段代码有很多问题,但仍然不能完全说明为什么会出现这样的错误。你检查堆栈跟踪了吗?

标签: reactjs redux


【解决方案1】:

React 和 React DOM 的不同步版本

你可以在你的 react projet 中运行 npm ls react-dom ,如果版本低于 16.8.0 它还不支持 Hooks

2- 不要在事件处理程序中调用 Hooks。

【讨论】:

    【解决方案2】:

    您的钩子必须始终位于功能组件的顶部。你可以通过简单地将“fName”的初始化移到你的钩子下面来解决这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-22
      • 1970-01-01
      • 2023-01-04
      • 2017-11-30
      • 2021-06-15
      • 2021-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多