React Native - useEffect будет отображать Home дважды - PullRequest
2 голосов
/ 02 мая 2020

Я хочу визуализировать мой функциональный компонент "Домой" после того, как я получу Данные от функции в "useEffect", но когда я установлю свои данные из функции в моем const, мой домашний компонент будет визуализироваться снова.

Если я удаляю оператор "set", он будет отображаться только один раз.

При повторном рендеринге HomeSrceen запускается оператор навигации, который находится в дочернем компоненте.

Может кто-нибудь объяснить мне, почему это произошло и как я решил эту проблему?

Мой код: HomeScreen. js

export function HomeScreen( navigation ) {

    const [item, setItem] = React.useState([]);
    console.log('fire home')

    React.useEffect(() => {
        getbannerdata()
        .then(res => setItem(res))
    }, []);


    return (
        <SafeAreaProvider>
            <SafeAreaView style={style.container}>
                <View>
                    <Banner data={item} navigation={navigation}/> 

                    <Text>Home</Text>
                </View>
            </SafeAreaView>
        </SafeAreaProvider>
    );
}

banneritem. js (навигация Оператор будет запущен)

const BannerItem = ({ item, navigation }) => {
    return (
        <View style={styles.cardView} onTouchStart={navigation.navigation.navigate('Setting')}>
            <Image style={styles.image} source={{uri: item.header}} />
            <TouchableOpacity>
            <View style={styles.textView}>
                <Text style={styles.itemTitle}>{item.title}</Text>
                <Text numberOfLines={2} style={styles.itemDescription}>{item.content}</Text>
            </View>
            </TouchableOpacity>
        </View>
    )
}

bannerdata. js

function getbannerdata(){
    console.log('fire bannerdata')
    return fetch ('http://192.168.178.46:8000/intranet/messages/', {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json',
        },

    })
        .then((res) => res.json())
        .then((resData) => {
            return resData;
        })
        .catch(error => console.log(error))

};

export { getbannerdata }

output Terminal

Finished building JavaScript bundle in 634ms.
Running application on Léons iPhone.
fire home
fire bannerdata
fire home

Ответы [ 2 ]

2 голосов
/ 02 мая 2020

Я хочу отобразить свой функциональный компонент "Домой" после того, как я получу Данные из функции ...

Затем вы должны получить данные из getbannerdata в родительском компоненте, и передать его HomeScreen в качестве реквизита. В HomeScreen вы ничего не можете сделать, чтобы предотвратить рендеринг компонента до прибытия данных из getbannerdata.

В целом, с компонентами у вас есть два варианта, когда нужно получить асинхронный процесс c их содержание:

  1. Сделайте это в компоненте и выполните рендеринг в случае, когда у компонента еще нет данных (возможно, с сообщением «загрузка» или аналогичным).

  2. Не создавайте компонент, пока у вас нет данных, что означает выполнение его в родительском элементе.

Пример # 1:

const { useState, useEffect } = React;

function getbannerdata() {
    return new Promise(resolve => {
        setTimeout(resolve, 800, "This is the banner");
    });
}

const HomeScreen = () => {
    const [banner, setBanner] = useState(null);
    
    useEffect(() => {
        getbannerdata().then(banner => setBanner(banner));
    }, [banner]);
    
    return (
        <div className="boxed">
            This is <code>HomeScreen</code>
            {banner && <div className="boxed">{banner}</div>}
        </div>
    );
};

const App = () => {
    
    return (
        <div className="boxed">
            This is <code>App</code>
            <HomeScreen />
        </div>
    );
};

ReactDOM.render(<App />, document.getElementById("root"));
.boxed {
    border: 1px solid black;
    padding: 4px;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

или с индикатором «загрузки»:

const { useState, useEffect } = React;

function getbannerdata() {
    return new Promise(resolve => {
        setTimeout(resolve, 800, "This is the banner");
    });
}

const HomeScreen = () => {
    const [banner, setBanner] = useState(null);
    
    useEffect(() => {
        getbannerdata().then(banner => setBanner(banner));
    }, [banner]);
    
    return (
        <div className="boxed">
            This is <code>HomeScreen</code>
            <div className="boxed">{banner ? banner : <em>Loading...</em>}</div>
        </div>
    );
};

const App = () => {
    
    return (
        <div className="boxed">
            This is <code>App</code>
            <HomeScreen />
        </div>
    );
};

ReactDOM.render(<App />, document.getElementById("root"));
.boxed {
    border: 1px solid black;
    padding: 4px;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

Пример # 2:

const { useState, useEffect } = React;

function getbannerdata() {
    return new Promise(resolve => {
        setTimeout(resolve, 800, "This is the banner");
    });
}

const HomeScreen = ({banner}) => {
    return (
        <div className="boxed">
            This is <code>HomeScreen</code>
            <div className="boxed">{banner}</div>
        </div>
    );
};

const App = () => {
    const [banner, setBanner] = useState(null);
    
    useEffect(() => {
        getbannerdata().then(banner => setBanner(banner));
    }, [banner]);
    
    return (
        <div className="boxed">
            This is <code>App</code>
            {banner && <HomeScreen banner={banner} />}
        </div>
    );
};

ReactDOM.render(<App />, document.getElementById("root"));
.boxed {
    border: 1px solid black;
    padding: 4px;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

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

0 голосов
/ 02 мая 2020

TJ Crowder прав, также потому, что происходящее совершенно нормально.

Поток того, что вы делаете, таков: - home перед useEffect фактически запущен - запуск useEffect - домашний рендеринг снова, потому что setItem был назван

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