React-native - экран на iOS не обновляется даже при вызове метода рендеринга - PullRequest
0 голосов
/ 16 июня 2020

Я работаю над мобильным приложением и столкнулся с проблемой, которую не знаю, как решить.

Мне нужно загрузить некоторые данные из API после создания экрана. Я делаю это в методе componentDidMount, который равен async, поэтому я могу использовать ключевое слово await. После этого я устанавливаю состояние, чтобы компонент Loader (который представляет собой просто модальный отображаемый текст) был скрыт, а экран повторно отображался с данными из API. Это отлично работает на устройствах Android. Но запуск этого кода на iOS (iPhone X) не работает. Вызываются методы рендеринга SomeScreen.js и Loader.js, и метод рендеринга Loader.js возвращает значение null (проверено с помощью консоли), но представление iPhone не обновляется. Модальный загрузчик все еще существует, даже если его метод рендеринга возвращает значение null. Я что-то не так делаю? Звонок this.foceUpdate() тоже не помогает.

SomeScreen.js

import React, {Component} from 'react';
import Loader from 'components/Loader/Loader';

export default class SomeScreen extends Component {

    constructor(props) {
        super(props);
        this.state = {
            loading: true,
            data: []
        };
    }

    async componentDidMount() {
        const data = await this.loadData();
        this.setState({loading: false, data: data})
    }

    async loadData() {
       //fetch and return data from API
    }

    render() {
        return (
            <SafeAreaView style={{flex: 1}}>
                <Loader loading={this.state.loading}/>
                //other rendering...
            </SafeAreaView>
        );
    }
}

Loader.js

import React, {Component} from 'react';
import {Modal, Text, View} from 'react-native';

export default class Loader extends Component {
    static defaultProps = {
        loading: false
    };

    render() {
        if (this.props.loading !== true) {
           return null;
        }
        return(
          <Modal
              transparent={false}
              animationType={'none'}
              visible={true}>
            <View style={{backgroundColor: "white", flex: 1, justifyContent: "center"}}>
              <Text>Loading data...</Text>
            </View>
          </Modal>
        )
    }
}

Ответы [ 2 ]

0 голосов
/ 16 июня 2020

Ну вот наконец-то я нашел ответ. Это потому, что есть открывающая анимация в модальном режиме на iOS, даже если я установил animationType как none. И если я изменю loading на false, до того, как эта анимация будет выловлена, модальное окно все равно будет открыто. Анимация занимает около 550 мс, а мой вызов API - около 200 мс.

Loader.js

import React, {Component} from 'react';
import {Modal, Text, View} from 'react-native';

export default class Loader extends Component {
    static defaultProps = {
        loading: false
    };

    constructor(props) {
        super(props);
        this.state = {
            loading: props.loading
        };
    }

    componentWillReceiveProps(nextProps, nextContext) {
        if (this.state.loading === true && nextProps.loading === false) {
            setTimeout(() => {
                this.setState({loading: false});
            }, 600);
        }
        if (this.state.loading === false && nextProps.loading === true) {
            this.setState({loading: true});
        }
    }

    render() {
        if (this.state.loading !== true) {
           return null;
        }
        return(
          <Modal
              transparent={false}
              animationType={'none'}
              visible={this.state.loading}>
            <View style={{backgroundColor: "white", flex: 1, justifyContent: "center"}}>
              <Text>Loading data...</Text>
            </View>
          </Modal>
        )
    }
}

В основном в моем решении я убеждаюсь, что модальное окно закрыто с задержкой 600 мс, поэтому он успевает завершить sh всплывающую анимацию.

0 голосов
/ 16 июня 2020

Я не уверен, почему вы видите разницу между iOS и Android, но я думаю, что вы могли бы попробовать упростить метод визуализации компонента Loader. Таким образом вы избежите использования вызовов 2 return.

import React, {Component, Fragment} from 'react';

render() {
  return (
      <Fragment>
        {this.props.loading ? null : {
         <Modal
           transparent={false}
           animationType={'none'}
           visible={this.props.loading}>
            <View style={{backgroundColor: "white", flex: 1, justifyContent: "center"}}>
              <Text>Loading data...</Text>
            </View>
          </Modal>
        }
      </Fragment>
    )
}

Приведенный выше код проверяет свойство loading и загружает компонент Modal или ничего. Я также добавил опору this.props.loading как значение к опоре visible вашего модального окна. Думаю, этого могло и не хватать.

...