useDispatch в функции handleClick

Как отправить действие при нажатии кнопки? Я хочу отправить действие, которое выполняет асинхронный вызов. Если это невозможно, каков практический способ?

import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";

import allActions from "../redux/actions/index";

import axios from "axios";

const useStyles = makeStyles((theme) => ({
  root: {
    flexGrow: 1,
    marginBottom: 10,
  },
}));

export default function ChatPreview({ chat }) {
  const [secondary, setSecondary] = React.useState(false);
  const lastMessageId = chat.messages.slice(-1)[0];
  const [message, setMessage] = useState(null);
  const [error, setError] = useState(null);
  const classes = useStyles();
  const user = useSelector((state) => state.user);
  const token = localStorage.getItem("IdToken").split(" ")[1];
  const dispatch = useDispatch;
  //Get otherUser
  let otherUser = {};
  chat.users.map((user_) => {
    if (user_.username !== user.username) otherUser = user_;
  });

  useEffect(() => {
    let headers = { Authorization: `Bearer ${token}` };

    axios
      .get(`/messages/message/${lastMessageId}`, { headers })
      .then((res) => {
        setMessage(res.data);
      })
      .catch((err) => {
        setError(err);
      });
  }, []);

  let primary = false;
  if (user && message) {
    if (user._id === message.author) primary = true;
  }

  const handleClick = () => {
    dispatch(allActions.inboxActions.deleteChat(chat._id, token));
  };

  const chatPreviewMarkup =
    message && user ? (
      <List>
        <ListItem>
          <ListItemAvatar>
            <Avatar alt={otherUser.username} src={otherUser.avatar} />
          </ListItemAvatar>
          <ListItemText
            primary={
              primary ? (message.read ? "read" : "unread") : message.content
            }
            secondary={secondary ? "Secondary text" : null}
          />
          <ListItemSecondaryAction>
            <IconButton edge="end" aria-label="delete">
              <DeleteIcon onClick={handleClick} />
            </IconButton>
          </ListItemSecondaryAction>
        </ListItem>
      </List>
    ) : (
      <p>...loading</p>
    );

  return chatPreviewMarkup;
}

возвращает следующую ошибку:

Ошибка: неверный вызов ловушки. Хуки могут быть вызваны только внутри тела функционального компонента. Это могло произойти по одной из следующих причин:

  1. У вас могут быть несовпадающие версии React и средства визуализации (например, React DOM)
  2. Вы можете нарушить правила ловушек
  3. У вас может быть несколько копий React в одном приложении.

2 ответа

Решение

Вам нужно позвонить useDispatch() вне обратного вызова, потому что перехватчики должны находиться на верхнем уровне компонента.

Вы почти сделали это, но вас сбила опечатка. Вам нужно изменить

const dispatch = useDispatch;

к

const dispatch = useDispatch();

Отсутствующие скобки означают, что вы на самом деле не звоните useDispatch пока внутри твоего handleClick. Переменная dispatch это сам хук, а не возвращаемое значение, поэтому, когда вы вызываете dispatch(allActions...) ты действительно звонишь useDispatch(allActions...) и появляется ошибка.

Как это

function MyComponent() {
  const dispatch = useDispatch()

  const handleClick = () => {
    dispatch(actionCreator())
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  )
}
Другие вопросы по тегам