UseReducer с асинхронным действием для выполнения запроса API

У меня есть форма, в которой есть поле с именем description, где при нажатии кнопки с именем query выполняется запрос POST, а затем отправляется текст в поле description в теле запроса.

Я использую для этого useReducer и не знаю, как структурировать действие и useEffect, когда пользователь нажимает кнопку query.

Action for querying the data(I am not sure what to return in this case)

switch (action.type) {
  case "query": {
    return {
      ...state,
    };
  }
}

Making the POST request and setting the JSON data in state which is then displayed(Takes as input the data from the field description)

const fetchData = async (desc) => {
  const response = await fetch("/rank", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ terms: desc }),
  }).catch((e) => console.info(e));
  const dataJSON = await response.json().catch((e) => console.info(e));
  if (response.ok) {
    console.info("OK");
  }
  if (!response.ok) {
    const error = (dataJSON && dataJSON.message) || response.status;
    return Promise.reject(error);
  }
  setData(dataJSON.data);
};

useEffect(() => {
  fetchData(description);
}, [description]);

Button for making the query

<Button
  type = "button"
  onClick = {() => {
    dispatch({ type: "query" });
  }}
>

Все это работает, но проблема в том, что хук useEffect срабатывает, даже когда я не нажимаю кнопку для запроса, поскольку я не знаю, как настроить для него действие.

🤔 А знаете ли вы, что...
JavaScript - это скриптовый язык программирования, разработанный Netscape Communications Corporation.


176
1

Ответ:

Решено

Не вижу смысла использоватьEffect для fetchData. вы хотите, чтобы эта функция вызывалась только при отправке, а не при каждом обновлении состояния.

также у вас есть своего рода setData. это приведет к дублированию состояния после использования useReducer. Я бы посоветовал удалить эти данные state, если вы используете здесь редуктор.

Я бы рекомендовал действие onClick вызывать fetchData и отправлять действие в случае успеха.

const fetchData = async () => {
  try {
  const response = await fetch("/rank", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ terms: description }),
  })
  const dataJSON = await response.json();
  if (response.ok) {
    console.info("OK");
  }
  if (!response.ok) {
    const error = (dataJSON && dataJSON.message) || response.status;
    throw error;
  }
  dispatch({ type: "query", data: dataJSON.data });
  } catch (error) {
    console.info(error)
  }
};

тогда ваш редуктор на вашем редукторе:

switch (action.type) {
  case "query":
    return {...state, action.data };
  default:
    return state;
}

вы также можете добавить некоторые дополнительные действия отправки, такие как loading, success и error, чтобы обрабатывать эти случаи, если это необходимо.