简体   繁体   中英

React Native - useEffect will render Home twice

I want to render my functional component "Home" after i get Data from a function in "useEffect", but when i set my data from the function in my const, my Home component will render again.

If i delete the "set" statement, it will only render once.

When the HomeSrceen render for the second time it will start a Navigation Statement that is in a child component.

Can anyone explain me why this happend and how i solve this problem?

My code: 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 (navigation Statement will be triggerd)

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

I want to render my functional component "Home" after i get Data from a function...

Then you must get the data from getbannerdata in the parent component, and pass it to HomeScreen as a prop. There's nothing you can do in HomeScreen to prevent the component being rendered before the data from getbannerdata arrives.

In general, with components, you have two choices when there's an async process to get their content:

  1. Do it in the component, and handle rendering the case where the component doesn't have the data yet (perhaps with a "loading" message or similar).

  2. Don't create the component until you have the data, which means doing it in the parent.

Example of #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>

or with a "loading" indicator:

 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>

Example of #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>

I found this article by Dan Abramov very useful. Ostensibly it's about useEffect , but really it's about the functional component lifecycle and hooks in general.

TJ Crowder is right, also because what is happening is perfectly normal.

The flow of what you're doing is: - home before useEffect is actually fired - firing of the useEffect - home rendering again because setItem was called

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM