Реакция setState из ловушки useState вызывает исключение при использовании в обратном вызове, переданном в подписку Rx JS - PullRequest
0 голосов
/ 21 января 2020

Я пишу несколько помощников для облегчения использования Rx JS в React.

Я написал настраиваемый хук , который позволяет отправлять обратные вызовы для подписки и получать обновления от Rx JS поток и обновить его. Этот хук также позволяет регистрировать обратные вызовы для ошибок потока и завершения . Они работали должным образом в тестах, но при написании правильного примера React выдает ошибку при ошибке потока, ошибку, которая должна быть обработана, и сообщение, отображаемое в пользовательском интерфейсе.

Это рабочая песочница с тот же код, что и ниже, с кнопками для обновления, отправки ошибки и завершения демонстрационного компонента

. Обратите внимание на строку, где происходит ошибка:

export default ({subject})=>{
    const [hasError, setHasError] = useState(false);
    const [complete, setComplete] = useState(false);
    const onError = (err)=>{
        setHasError(true); // <-------------- Commenting this line avoids the error!
        console.log('Value handled error',err);
    };
    const onComplete = ()=>{
        setComplete(true);
        console.log('Value handled completion');
    };
    const [val,setVal] = useSubject(subject,onError,onComplete);
    const onClick = ()=>setVal(val+1);
    return (
        <span>
            {val}
            {hasError?' An Error ocurred ':null}
            {complete?' Stream has completed ':null}
            <button onClick={onClick}>increment</button>
            <button onClick={()=>subject.error(5)}>Generate error</button>
            <button onClick={()=>subject.complete()}>Complete</button>
        </span>
    );
}

Пользовательский хук следует:

export const useSubject = (subject,onError,onComplete) => {
  const [value, setValue] = useState(subject.getValue());
  useEffect(() => {
    const subFn = { next: data => setValue(data) };
    if (onError) { subFn.error = err => onError(err); }
    if (onComplete) { subFn.complete = () => onComplete(); }
    const sub = subject.pipe(skip(1)).subscribe(subFn);  
    return () => sub.unsubscribe();
  });
  const newSetState = state => subject.next(state);
  return [value, newSetState];
};

Сообщение об ошибке от React не очень полезно, и если я правильно понимаю, границы ошибок будут только помогите мне отобразить лучший пользовательский интерфейс, но я заинтересован в исправлении ошибки, не содержащей ее.

С строкой, которая обновляет состояние, закомментировано, обратный вызов работает и записывает на консоль без проблем, в то время как если Я обновляю состояние в обратном вызове (чтобы я мог управлять обновлением пользовательского интерфейса), происходит сбой. Я перепробовал много обходных путей и сдвиг ответственности между ловушкой и компонентом, но в конце мне нужно обновить состояние в компоненте, что вызывает cra sh. Как ни странно, завершение потока также обновляет состояние с помощью очень похожего обратного вызова, но этот работает.

Что я делаю не так? Это можно помочь или обойти?

1 Ответ

0 голосов
/ 21 января 2020

В Rx JS любая ошибка или полный вызов в основном "убьют" поток. После того, как вы setHasError(true) в своем компоненте «Sample», он перерисовывает и снова запускает эту строку:

const [val, setVal] = useSubject(subject, onError, onComplete);

этот хук начинается с:

const [value, setValue] = useState(subject.getValue());

Где getValue () на субъект с ошибкой выдает ошибку.

...