【问题标题】:FlatList not showing data correctly after data changes数据更改后 FlatList 无法正确显示数据
【发布时间】:2020-12-03 07:08:11
【问题描述】:

我正在从数据库中获取数据并将其显示在 FlatList 中。每当我从数据中添加或删除某些内容时,FlatList 中的数据都不会正确显示。 每当我删除某些东西时,它都会显示一个空列表。 每当我添加一些东西时,它只会显示新添加的数据——没有别的。

我正在使用firebase实时数据库并使用我得到的数据如下:

firebase.database().ref(`/wordlists/${editKey}`).on('value', snap => {
    if (snap.val() !== null) {
        setIsLoading(false);
        const val = snap.val().words;
        const data = [];
        Object.keys(val).forEach(key => {
            data.push({ key, word: val[key].word });
        })
        setWords(data);
        // setWords([...data]) doesn't work either.
    }
}) 

我的平面列表如下所示:

<FlatList 
    data={words}
    renderItem={renderItem}
    keyExtractor={item => item.key}
    extraData={words}
/>

当我 console.log() 获取数据时,我总是得到我想要显示的数据,但 FlatList 无法正确显示。

当我使用扩展运算符和/或 extraData 时,它也不起作用。

因为有人在这里要求它是整个文件(我省略了样式和导入)

const EditList = ({ editKey }) => {

    const [wordlist, setWordlist] = useState(0);
    const [refresh, setRefresh] = useState(false);
    const [words, setWords] = useState([]);
    const [wordLoading, setWordLoading] = useState({ loading: false });
    const [loading, setIsLoading] = useState(false);
    const [btnLoading, setBtnLoading] = useState(false);
    const [word, setWord] = useState('');

    useEffect(() => {
        if (editKey !== 0) {
            setIsLoading(true);
            firebase.database().ref(`/wordlists/${editKey}`).on('value', snap => {
                if (snap.val() !== null) {
                    setIsLoading(false);
                    setWordlist({...snap.val()});
                    const val = snap.val().words;
                    const data = [];
                    Object.keys(val).forEach(key => {
                        data.push({ key, word: val[key].word });
                    })
                    setWords([...data]);
                    setRefresh(!refresh);
                    console.log(data, 'DATA');
                }
            })
        }
    }, [editKey])

    const onAdd = () => {
        setBtnLoading(true);
        firebase.database().ref(`/wordlists/${editKey}/words`).push({ word })
        .then(() => {
            setBtnLoading(false);
            setWord('');
            setRefresh(!refresh);
        })
    }

    const onDelete = (key) => {
        setWordLoading({ key, loading: true });
        firebase.database().ref(`/wordlists/${editKey}/words/${key}`).remove().then(() => {
            setWordLoading({ loading: false });
            setRefresh(!refresh);
        });
    }

    const renderItem = ({ item }) => (
        <ItemWrapper>
            <ItemWord>{ item.word }</ItemWord>
            <DeleteView onPress={() => onDelete(item.key)}>
                { wordLoading.loading && wordLoading.key === item.key ?
                    <ActivityIndicator size="small" /> :
                    <DIcon name="trash-2" size={24} />
                }
            </DeleteView>
        </ItemWrapper>
    )

    const createData = (words) => {
        const data = [];
        if (typeof words !== 'undefined') {
            Object.keys(words).forEach(key => {
                const obj = { key, word: words[key].word };
                data.push(obj);
            })
        }
        console.log(data, 'DATADATADATA');
        return data;
    }

    if (editKey === 0) {
        return (
            <NokeyWrapper>
                <NoKeyText>No list selected...</NoKeyText>
            </NokeyWrapper>
        )
    }
    if (loading) {
        return (
            <NokeyWrapper>
                <ActivityIndicator size="large" />
            </NokeyWrapper>
        )
    }
    return (
        <Wrapper 
            behavior={Platform.OS == "ios" ? "padding" : "height"} 
            keyboardVerticalOffset={Platform.OS === 'ios' && 180}
        >
            <WordListName>{wordlist.listName}</WordListName>
            <FlatListWrapper>
                <FlatList 
                    data={words}
                    renderItem={renderItem}
                    keyExtractor={item => item.key}
                    //extraData={refresh}
                    extraData={words}
                />
            </FlatListWrapper>
            <AddWordWrapper>
                <SInput value={word} onChangeText={(text) => setWord(text)} />
                <Button onPress={() => onAdd()} loading={btnLoading}>
                    <Feather name="plus" size={24} color="black" />
                </Button>
            </AddWordWrapper>
        </Wrapper>
    )
};

export default EditList;

【问题讨论】:

  • 试试这个 - setWords([...data]);
  • 如何更新words 数组?确保你没有改变它。并尝试使用FlatlistextraData 道具
  • @SarunUK 感谢您的评论。我已经尝试过并再次尝试,但仍然显示相同的内容。
  • @Yasmin 我已经试过了。使用 extraData 没有帮助。我正在通过 setWords(data) 更新数组。我也尝试使用像 Sarun 建议的扩展运算符( setWords([...data])) 但它仍然不起作用。
  • 你能展示整个代码吗?

标签: reactjs react-native firebase-realtime-database


【解决方案1】:

您需要为此实例使用 useRef,因为新的“单词”不在 .on('value') 调用中。

 const [words, _setWords] = useState([]);
 const wordRef = useRef(words)


 //function to update both wordRef and words state
 const setWords = (word) => {
        
      wordRef = word
      _setWords(word)
 } 



useEffect(() => {

if (editKey !== 0) {
    setIsLoading(true);
    let data = wordRef   //create a temp data variable
    firebase.database().ref(`/wordlists/${editKey}`).on('value', snap => {
        if (snap.val() !== null) {
            setIsLoading(false);                 
            setWordlist({...snap.val()});
            const val = snap.val().words;

            Object.keys(val).forEach(key => {
                data.push({ key, word: val[key].word });
            })
            setWords(data);
            setRefresh(!refresh);
            console.log(data, 'DATA');
        }
    })

    return () => firebase.database().ref(`/wordlists/${editKey}`).off('value') // <-- need to turn it off.
}
}, [editKey, wordRef])

如果不刷新,您可能需要使用相同的方法更改 setRefresh 等。

【讨论】:

    【解决方案2】:

    经过多次尝试,我发现问题出在其他地方。在我的 renderItem() 中以某种方式使用 'flex: 1' 导致了这个问题。我实际上也在 github 上发现了这个问题:GitHub React Native issues

    因此,从元素中删除 'flex: 1' 后,一切都按预期显示。

    // before
    const renderItem = ({ item }) => (
        <ItemWrapper style={{ flex: 1, flexDirection: row }}>
            <ItemWord>{ item.word }</ItemWord>
        </ItemWrapper>
    )
    
    // after
    const renderItem = ({ item }) => (
        <ItemWrapper style={{ width: '100%' }}>
            <ItemWord>{ item.word }</ItemWord>
        </ItemWrapper>
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-28
      • 2011-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多