简体   繁体   中英

extraData hook not working for one of 2 flatLists

So I'm trying to build a news feed reader for my websites. it's pretty basic just 2 flatLists. One vertical that lists the articles, the other horizontal that lists the sites. When clicking on the horizontal items it is updating 2 different state settings. These 2 settings are set as extraData for the flatLists. The horizontal one rerenders after a press but the vertical one doesn't.

The onPress is updating both the site and selectedId states and while the sites flatList rerenders and shows the background color change, the artile flatList does not rerender with the new feed.

Here is the code.

import { StatusBar } from 'expo-status-bar';
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, Image, View, FlatList, TouchableOpacity, Avatar, Dimensions } from 'react-native';
import Header from './components/header';
import Article from './components/article';

export default function App() {
  const [isLoading, setLoading] = useState(true);
  const [articles, setArticles] = useState([]);
  const [site, setSite] = useState('https://minedhash.com/feed');
  useEffect(() => {
    fetch('https://api.rss2json.com/v1/api.json?rss_url='+site)
      .then((response) => response.json())
      .then((json) => setArticles(json.items))
      .catch((error) => console.error(error))
      .finally(() => setLoading(false));
  }, []);

  const [selectedId, setSelectedId] = useState(2);
  const nftImg = require('assets/NFT.png');
  const mhImg = require('assets/MH.png');
  const cntImg = require('assets/CNT.png');
  const sntImg = require('assets/SNT.png');
  const entImg = require('assets/ENT.png');
  const bscImg = require('assets/BSC.png');
  const ethImg = require('assets/ETH.png');
  const fafImg = require('assets/FAF.png');
  const pntImg = require('assets/PNT.png');
  const cenImg = require('assets/CEN.png');
  const siteList = [
    {'id': 1, 'name': 'NFT News Today', 'avatar': nftImg, 'color': '#ffffff', 'bgcolor': '#6856dd', 'url': 'https://nftnewstoday.com/feed'},
    {'id': 2, 'name': 'Mined Hash', 'avatar': mhImg, 'color': '#000000', 'bgcolor': '#ff5757', 'url': 'https://minedhash.com/feed'},
    {'id': 3, 'name': 'Cardano News Today', 'avatar': cntImg, 'color': '#000000', 'bgcolor': '#3cc8c8', 'url': 'https://cardanonewstoday.com/feed'},
    {'id': 4, 'name': 'Solana News Today', 'avatar': sntImg, 'color': '#000000', 'bgcolor': '#7783d4', 'url': 'https://solananewstoday.com/feed'},
    {'id': 5, 'name': 'Elrond News Today', 'avatar': entImg, 'color': '#ffffff', 'bgcolor': '#090223', 'url': 'https://elrondnews.com/feed'},
    {'id': 6, 'name': 'BSC Chain', 'avatar': bscImg, 'color': '#ffffff', 'bgcolor': '#2b2e35', 'url': 'https://bscchainnews.com/feed'},
    {'id': 7, 'name': 'Ethereum News Today', 'avatar': ethImg, 'color': '#000000', 'bgcolor': '#d8cd51', 'url': 'https://ethereumnewstoday.net/feed'},
    {'id': 8, 'name': 'Finance and Freedom', 'avatar': fafImg, 'color': '#ffffff', 'bgcolor': '#0000fe', 'url': 'https://financeandfreedom.org/feed'},
    {'id': 9, 'name': 'Polkadat News Today', 'avatar': pntImg, 'color': '#ffffff', 'bgcolor': '#1e1e1e', 'url': 'https://polkadotnewstoday.com/feed'},
    {'id': 10, 'name': 'Crypto Exchange News Today', 'avatar': cenImg, 'color': '#ffffff', 'bgcolor': '#0277bd', 'url': 'https://cryptoexchangenews.net/feed'},
]

  const Item = ({ item, onPress, backgroundColor, textColor }) => (
    <TouchableOpacity onPress={onPress} style={[styles.site, backgroundColor]}>
      <Image style={styles.tinyLogo} source={item.avatar} resizeMode='cover' />
      <Text style={[styles.title, textColor]}>{item.name}</Text>
    </TouchableOpacity>
  );

  const renderItem = ({ item }) => {
    const backgroundColor = item.id == selectedId ? "#373361" : "#05003a";
    const color = 'white';

    return (
      <Item
        item={item}
        onPress={function(){
            setSelectedId(item.id);
            setSite(item.url);
        }}
        backgroundColor={{ backgroundColor }}
        textColor={{ color }}
      />
    );
  };

  return (
    <View style={styles.container}>
      {/* header */}
      <Header />
      <View style={styles.content}> 
        <View style={styles.articleList}>
          {/* Content */}
          {isLoading ? <Text>Loading...</Text> : 
          ( <FlatList 
              data={articles}
              renderItem={({ item }) => (
                <Article item={item}/>
              )}
              keyExtractor={(item, index) => index.toString()}
              extraData={site}
            />
          )}
        </View>
      </View>
      <View style={styles.siteBar}>
        {/* siteBar */}
            <FlatList
                horizontal
                data={siteList}
                renderItem={renderItem}
                keyExtractor={(item) => item.id.toString()}
                extraData={selectedId}
            />
      </View>
      <StatusBar style='light' />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  content: {
    paddingLeft: 20,
    paddingRight: 20,
  },
  articleList: {
    marginTop: 10,
    marginBottom: 10,
    height: Dimensions.get('window').height - 190
  },
  siteBar: {
    height: 140,
    width: Dimensions.get('window').width,
    backgroundColor: '#fff',
  },
  site: {
    height: 200,
    width: 110,
    marginLeft: 5,
    padding: 5,
    borderColor: '#fff',
    borderWidth: 1,
    borderRadius: 10,
    textAlign: 'center',
  },
  title: {
    textAlign: 'center',
  },
  tinyLogo: {
    height: 90,
    width: 90,
    marginLeft: 5,
    marginTop: 5
  }
});

As per the code observation, I can see there might dependency issue in useEffect code.

Have a try by adding site dependency in the useEffect dependency list.

try ex.

useEffect(() => {
    fetch('https://api.rss2json.com/v1/api.json?rss_url=' + site)
      .then((response) => response.json())
      .then((json) => setArticles(json.items))
      .catch((error) => console.error(error))
      .finally(() => setLoading(false))
  }, [site])

instead of

useEffect(() => {
    fetch('https://api.rss2json.com/v1/api.json?rss_url=' + site)
      .then((response) => response.json())
      .then((json) => setArticles(json.items))
      .catch((error) => console.error(error))
      .finally(() => setLoading(false))
  }, [])

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