React-Native Создание декларации setInterval с помощью React Hooks - PullRequest
1 голос
/ 14 мая 2019

Я играю с React Hooks более нескольких часов, возможно, я столкнулся с интригующей проблемой: использование setInterval просто не работает, как я ожидал, с response-native

function Counter() {
  const [time, setTime] = useState(0);
  const r = useRef(null);
  r.current = { time, setTime };
  useEffect(() => {
    const id = setInterval(() => {
      console.log("called");
      r.current.setTime(r.current.time + 1);
    }, 1000);
    return () => {
      console.log("cleared");
      clearInterval(id);
    };
  }, [time]);

  return <Text>{time}</Text>;
}

Приведенный выше код должен очищатьInterval при каждом изменении состояния time. Отлично работает на ReactJS, но на React-native Я получаю сообщение об ошибке: "Callback() it's not a function"

введите описание изображения здесь

В Reactjs он работает, как и ожидалось

https://codesandbox.io/s/z69z66kjyx

"dependencies": {
    "react": "16.8.3",
    "react-native": "^0.59.6",
    ...}

Обновление: я пытался использовать ссылку, как в этом примере, но все еще получаюта же ошибка

const [time, setTime] = useState(0);
        useInterval(() => {
            setTime(time +1);
        });

        return (<Text>{time}</Text>);
}

function useInterval(callback) {
    const savedCallback = useRef();

    // Remember the latest function.
    useEffect(() => {
        savedCallback.current = callback;
    }, [callback]);

    // Set up the interval.
    useEffect(() => {
            let id = setInterval(()=>savedCallback.current(), delay);
            return () => clearInterval(id);
    });
}

Ответы [ 2 ]

2 голосов
/ 14 мая 2019

Поскольку вы изменяете DOM через ссылки на узлы DOM, и мутация DOM изменит внешний вид узла DOM между отображаемым временем и вашими эффектами, мутирующими его.тогда вам не нужно использовать useEffect, вы захотите использовать useLayoutEffect

useLayoutEffect, это выполняется синхронно сразу после того, как React выполнил все мутации DOM.

import React, {useState, useLayoutEffect,useRef} from 'react';
import { Text} from 'react-native';

const [time, setTime] = useState(0);
        useInterval(() => {
            setTime(time +1);
        });

        return (<Text>{time}</Text>);
}

function useInterval(callback) {
    const savedCallback = useRef();

    // Remember the latest function.
    useLayoutEffect(() => {
        savedCallback.current = callback;
    }, [callback]);

    // Set up the interval.
    useLayoutEffect(() => {
            let id = setInterval(()=>{
              console.log('called');
              return savedCallback.current();
            }, delay);
            return () => {
                console.log('cleared');
                return clearInterval(id);
            }
    });
}

если вы просто используете useEffect и получаете эту ошибку

Uncaught TypeError: callback is not a function at flushFirstCallback (scheduler.development.js:348) at flushWork (scheduler.development.js:441) at MessagePort.channel.port1.onmessage (scheduler.development.js:188)

Это ошибка в RN из-за неправильной версии scheduler, К сожалению, RN не сделалЯ не могу явно зависеть от версии планировщика. Дэн Абрамов уже исправил эту ошибку в версии планировщика "0.14.0"

Чтобы решить эту проблему, просто введите следующую команду

npm install scheduler@0.14.0 --save

Или попробуйте добавить "scheduler": "0.14.0" в свойpackage.json in dependencies и перезапуск вашего менеджера пакетов

0 голосов
/ 14 мая 2019

Вы должны иметь возможность использовать переменные ловушки состояния в ловушке эффекта, поскольку они находятся в области видимости.

useRef : мутации здесь не отслеживаются, поэтому они не вызывают повторное рендеринг.

Пример счетчика CodeSandbox

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

Я обновил свою песочницу, чтобы использовать useRef в том виде, как у вас, ваш хук useEffect вызывал срабатывание функции очистки при каждом рендере, поэтому удалили зависимость. Теперь вы заметите, что видите только «позвонил», пока не обновитесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...