Обработка ошибок с использованием React's useState - PullRequest
1 голос
/ 07 марта 2019

Если у меня есть компонент, который похож на ниже:

import React, { useState } from "react";
import ReactDOM from "react-dom";

function calculateNewValueAndMaybeError(test) {
  try {
    // do something with test that might error
    // const newTest = functionThatMightError(...)
    // if it doesn't error, return { value: newTest, error: '' }
  } catch (err) {
    // is it correct to now return this in case of error?
    // return { value: test.value, error: 'Something went wrong' }
  }
}

function App() {
  const [test, setTest] = useState({ value: "", error: "" });
  return (
    <div>
      <p>Test: {test.value}</p>
      <p>Error: {test.error}</p>
      <button onClick={() => setTest(calculateNewValueAndMaybeError(test))}>
        Click me
      </button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

И у меня есть кнопка, которая должна изменять состояние моей переменной с именем test, есть ли способ обработки ошибок без необходимости постоянно обойти объект со значением и ошибкой внутри?

В противном случае, это не приводит к необходимому коду, как показано ниже:

onChange={() => setTest({ value: e.target.value, error: test.error })}

Где вы хотите обновить значение test.value, но сохранить значение test.error.

Я чувствую, что что-то очевидно, что мне не хватает.

Спасибо!

1 Ответ

2 голосов
/ 07 марта 2019

Необходимость слияния двух состояний предполагает, что они должны обрабатываться как разные состояния:

function App() {
  function calculateNewValueAndMaybeError(test) {
    try {
      ...
      setValue(...);
      setError(null);
    } catch (err) {
      setError('Something went wrong');
    }
  }

  const [error, setError] = useState(null);
  const [value, setValue] = useState('');
  return (
    <div>
      <p>Test: {value}</p>
      <p>Error: {error}</p>
      <button onClick={() => setTest(calculateNewValueAndMaybeError(test))}>
        Click me
      </button>
    </div>
  );
}

Или для объединения поля error можно использовать пользовательский хук состояний:

const useErrorState = initialState => {
  const [state, setState] = useState({ ...initialState, error: null });
  const setErrorState = useCallback(stateUpdater => {
    if (typeof stateUpdater === 'function') {
      setState(state => {
        try {
          return {error: null, ...stateUpdater(state) };
        } catch (error) {
          return {...state, error };
        }
      });
    } else {
      setState({error: null, ...stateUpdater });
    }
  }, []);

  return [state, setErrorState];
}

Другая возможность - перенести обработку ошибок в родительский компонент (возможно, с компонентом более высокого порядка) и перехватывать там ошибки.

...