【问题标题】:React Native - useEffect will render Home twiceReact Native - useEffect 将渲染 Home 两次
【发布时间】:2020-08-16 19:08:03
【问题描述】:

我想在从“useEffect”中的函数获取数据后渲染我的功能组件“Home”,但是当我从我的 const 中的函数设置数据时,我的 Home 组件将再次渲染。

如果我删除“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 }

输出终端

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

【问题讨论】:

    标签: javascript reactjs react-native render


    【解决方案1】:

    我想在从函数中获取数据后呈现我的函数组件“主页”...

    然后你必须从父组件中的getbannerdata 获取数据,并将其作为prop 传递给HomeScreen。在HomeScreen 中您无法阻止组件在来自getbannerdata 的数据到达之前被渲染。

    通常,对于组件,当有一个异步进程来获取其内容时,您有两种选择:

    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>

    我发现 Dan Abramov 的 this article 非常有用。表面上它是关于useEffect,但实际上它是关于功能组件生命周期和一般钩子。

    【讨论】:

      【解决方案2】:

      T.J Crowder 是对的, 也因为发生的事情是完全正常的。

      您正在做的事情的流程是: - 在 useEffect 被实际触发之前的 home - 触发 useEffect - 因为调用了 setItem,所以再次进行 home 渲染

      【讨论】:

        猜你喜欢
        • 2022-11-26
        • 1970-01-01
        • 2021-10-26
        • 2021-03-18
        • 1970-01-01
        • 2021-09-09
        • 1970-01-01
        • 2021-11-14
        相关资源
        最近更新 更多