Подтвердить что ты не робот

Установка таймера в течение длительного периода времени, то есть нескольких минут

Я хочу использовать firebase auth с реакцией native на Login и Signup, но я получил желтую ошибку:

Установка таймера в течение длительного периода времени, т.е. нескольких минут, является проблемой производительности и корректности на Android, поскольку она удерживает модуль таймера активным, а таймеры могут вызываться только тогда, когда приложение находится на переднем плане. См. (https://github.com/facebook/react-native/issues/12981) для получения дополнительной информации. (Saw setTimeout с длительностью 111862мс)

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

  export default class Login extends Component {
        constructor(props) {
            super(props)
            this.state = {
                email: '',
                password: '',
                response: ''
            }
            this.signUp = this.signUp.bind(this)
            this.login = this.login.bind(this)
        }
        async signUp() {
            try {
                await firebase.auth().createUserWithEmailAndPassword(this.state.email, this.state.password)
                this.setState({
                    response: 'Account Created!'
                })
                setTimeout(() => {
                    this.props.navigator.push({
                        id: 'App'
                    })
                }, 1500)
            } catch (error) {
                this.setState({
                    response: error.toString()
                })
            }
        }
        async login() {
            try {
                await firebase.auth().createUserWithEmailAndPassword(this.state.email, this.state.password)
                this.setState({
                    response: 'user login in'
                })
                setTimeout(() => {
                    this.props.navigator.push({
                        id: 'App'
                    })
                })

            } catch (error) {
                this.setState({
                    response: error.toString()
                })
            }

        }
        render() {
            return (
                <View style={styles.container}>
                    <View style={styles.containerInputes}>
                        <TextInput
                            placeholderTextColor="gray"
                            placeholder="Email"
                            style={styles.inputText}
                          //  onChangeText={(email) => this.setState({ email })}
                            onChangeText={(email) => {console.log(email);}}
                        />
                        <TextInput
                            placeholderTextColor="gray"
                            placeholder="Password"
                            style={styles.inputText}
                            password={true}
                            onChangeText={(password) => this.setState({ password })}
                        />
                    </View>
                    <TouchableHighlight
                        onPress={this.login}
                        style={[styles.loginButton, styles.button]}
                    >
                        <Text
                            style={styles.textButton}
                        >Login</Text>
                    </TouchableHighlight>
                    <TouchableHighlight
                        onPress={this.signUp}
                        style={[styles.loginButton, styles.button]}
                    >
                        <Text
                            style={styles.textButton}
                        >Signup</Text>
                    </TouchableHighlight>
                </View>
            )
        }
    }

Я сообщил команде Firebase Google: (https://github.com/firebase/firebase-js-sdk/issues/97)

4b9b3361

Ответ 1

Джош Краутер, инженер-программист из Google, сказал:

Использование многошаговой короткой длительности setTimeouts на самом деле не решает проблему. Модуль Timer по-прежнему остается активным, а приложение по-прежнему подвержено проблемам с производительностью, указанным в предупреждении. Проблема здесь в том, что у нас есть варианты использования, для которых требуются длительные таймеры, и реагирующая система не оптимизируется для этого варианта использования.

Итак, сеть всего, что есть: эта ошибка не может быть исправлена здесь, мы можем только обойти ошибку, есть доступные обходные пути (см. Установка таймера на длительный период времени, т.е. несколько минут), которые отключают предупреждение. Выполнение работы по отключению предупреждения в нашем коде не помогает решить проблему (кроме отключения предупреждения) и добавляет дополнительный код/​​вес SDK, который совершенно не нужен.

Я бы порекомендовал присоединиться к проблеме, упомянутой выше (например, facebook/реагировать на родной язык # 12981), если вам не удобно с предоставленным обходным путем

Ответ 2

Это исправляет желтое поле и журнал консоли. Это даже исправляет это для Экспо.

Просто поместите следующий скрипт в начало вашей кодовой базы.

import { YellowBox } from 'react-native';
import _ from 'lodash';

YellowBox.ignoreWarnings(['Setting a timer']);
const _console = _.clone(console);
console.warn = message => {
  if (message.indexOf('Setting a timer') <= -1) {
    _console.warn(message);
  }
};

Ответ 3

У меня такая же проблема, и я думаю, что это проблема веб-SDK для firebase, поэтому я решил отказаться от SDK для базы данных firebase, потому что он работает в js-потоке, а не в ответном потоке.

И я нашел react-native-firebase. Это лучше, чем firebase web SDK с более высокой производительностью, и эта проблема ушла.

Ответ 4

rigobcastro решил это. он сказал, чтобы добавить эту строку кода в корневой компонент, и если вы спросите, где вы можете добавить его, вы можете добавить код в метод конструктора, например:

constructor() {
     super();

     console.ignoredYellowBox = [
         'Setting a timer'
     ];
 }

или

import BackgroundTimer from 'react-native-background-timer';

setTimeout = BackgroundTimer.setTimeout.bind(BackgroundTimer)
setInterval = BackgroundTimer.setInterval.bind(BackgroundTimer)
clearTimeout = BackgroundTimer.clearTimeout.bind(BackgroundTimer)
clearInterval = BackgroundTimer.clearInterval.bind(BackgroundTimer)

Ответ 5

Другой подход заключается в использовании модуляact-native-ignore-warnings.

https://github.com/jamrizzi/react-native-ignore-warnings

https://www.npmjs.com/package/react-native-ignore-warnings

Это даже работает для приложений Expo.

Вы бы использовали это следующим образом. , ,

import ignoreWarnings from 'react-native-ignore-warnings';

ignoreWarnings('Setting a timer');

может работать с Android тоже..?

Ответ 6

В login() ваш вызов setTimeout() пропускает значение интервала. Как правило, браузеры теперь не запускают тайм-ауты/интервалы, если окно/вкладка находится в фоновом режиме, или, по крайней мере, они не должны быть своевременными. Это необходимо для предотвращения злоупотребления сценариями и снижения энергопотребления сценариев, которые могут опрашивать.

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

Желтое поле - потому что вы устанавливаете слишком длинный таймер в соответствии с сообщением (почти две минуты), и это вряд ли будет контекстуально тем, что вы хотите. Среда JS предупреждает вас, что то, что вы делаете, не соответствует вашим намерениям. Вы можете отключить предупреждение, если это то, что вы хотите.

Ответ 7

Я думаю, что наиболее близким решением этой проблемы (пока RN не исправит это внутренне) является решение, упомянутое здесь.

// add this code to your project to reset all timeouts
const highestTimeoutId = setTimeout(() => ';');
for (let i = 0; i < highestTimeoutId; i++) {
    clearTimeout(i); 
}

При использовании этого - против вызова Firebase я все еще получаю одно предупреждение желтого ящика (по истечении установленного времени), но любые параллельные предупреждения никогда не приходят после этого. Я не уверен, что вызов этого пункта может привести к тому, что единственное предупреждение также может не сработать, но никаких одновременных предупреждений больше не происходит после async вызовов Firebase.

Ответ 8

import { YellowBox } from 'react-native';

construct() {
    YellowBox.ignoreWarnings(['Setting a timer']);
}

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

Игнорировать это не лучший подход, но если вы используете Firebase Realtime Database. Они пытаются решить эту проблему с помощью своей библиотеки, хотя этой проблеме уже 2 года.

Ответ 9

Обойти проблему с желтым предупреждением "Установка таймера".

скопировать и импортировать следующий файл (так быстро, как вы можете ;-))

import {Platform, InteractionManager} from 'react-native';

const _setTimeout = global.setTimeout;
const _clearTimeout = global.clearTimeout;
const MAX_TIMER_DURATION_MS = 60 * 1000;
if (Platform.OS === 'android') {
    // Work around issue 'Setting a timer for long time'
    // see: https://github.com/firebase/firebase-js-sdk/issues/97
    const timerFix = {};
    const runTask = (id, fn, ttl, args) => {
        const waitingTime = ttl - Date.now();
        if (waitingTime <= 1) {
            InteractionManager.runAfterInteractions(() => {
                if (!timerFix[id]) {
                    return;
                }
                delete timerFix[id];
                fn(...args);
            });
            return;
        }

        const afterTime = Math.min(waitingTime, MAX_TIMER_DURATION_MS);
        timerFix[id] = _setTimeout(() => runTask(id, fn, ttl, args), afterTime);
    };

    global.setTimeout = (fn, time, ...args) => {
        if (MAX_TIMER_DURATION_MS < time) {
            const ttl = Date.now() + time;
            const id = '_lt_' + Object.keys(timerFix).length;
            runTask(id, fn, ttl, args);
            return id;
        }
        return _setTimeout(fn, time, ...args);
    };

    global.clearTimeout = id => {
        if (typeof id === 'string' && id.startsWith('_lt_')) {
            _clearTimeout(timerFix[id]);
            delete timerFix[id];
            return;
        }
        _clearTimeout(id);
    };
}

Ответ 10

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

componentDidMount() { console.disableYellowBox = true; ... }

Ответ 11

В Expo он работал только для меня с этим кодом, который я получил от ответа CopyJosh в соответствующем выпуске Github:


class App extends Component {
  constructor() {
    super();
    YellowBox.ignoreWarnings(['Setting a timer']);
    console.ignoredYellowBox = ['Setting a timer'];
    const consoleClone = clone(console);
    console.warn = message => {
      if (message.indexOf('Setting a timer') <= -1) {
        consoleClone.warn(message);
      }
    };
  }

  render() {
    return (...);
  }
}

export default App;

Ключ должен поместить код в функцию constructor точки входа в App.