簡體   English   中英

React Native 在純組件中更新 FlatList 數據

[英]React Native update FlatList data in pure component

我對 React Native 有點陌生,並且一直遇到 FlatList 的這個問題,我想更新它使用的數據源並讓它自我更新。 我的情況是有一個我想用 FlatList 顯示的項目列表,然后每個項目都是可選的。 我見過的大多數示例都是使用組件,建議將state添加到extraData以解決此問題。 但是,我正在使用純組件並嘗試查看在這種情況下是否有任何解決方案。 按照我創建的示例項目。 在這個例子中,新聞發生了, data被更新了,但是 FlatList 沒有反映data的變化。

import { findIndex } from 'lodash'
import React, { useState } from 'react'
import {
  SafeAreaView,
  StyleSheet,
  View,
  Text,
  StatusBar,
  FlatList,
  Pressable,
} from 'react-native'

import {
  Colors,
} from 'react-native/Libraries/NewAppScreen'

var array = require('lodash/array')

const App = () => {
  const [data, setData] = useState([
    {
      name: "Foo",
      id: '1',
      isSelected: false
    },
    {
      name: "Boo",
      id: '2',
      isSelected: false
    },
    {
      name: "Koo",
      id: '3',
      isSelected: false
    },
    {
      name: "Poo",
      id: '4',
      isSelected: false
    },
    {
      name: "Too",
      id: '5',
      isSelected: false
    },
    {
      name: "Qoo",
      id: '6',
      isSelected: false
    },
  ])

  const tappedItem = (item) => {
    const itemIndex = data.findIndex((i) => i.id == item.id)
    const newItem = data[itemIndex]
    newItem.isSelected = !newItem.isSelected
    data[itemIndex] = newItem
    setData(data)
  }

  const renderItem = (item) => {
    return (
      <Pressable onPress={() => tappedItem(item.item)}>
        <View style={[styles.sectionContainer, { backgroundColor: item.item.isSelected ? 'pink' : 'lightgray' }]}>
          <Text style={styles.sectionTitle}>{item.item.name}</Text>
        </View>
      </Pressable>
    )
  }

  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <View style={styles.body}>
          <FlatList
            data={data}
            keyExtractor={item => item.id}
            renderItem={renderItem}
            extraData={data}
          />
        </View>
      </SafeAreaView>
    </>
  )
}

const styles = StyleSheet.create({
  body: {
    backgroundColor: Colors.white,
  },
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
    color: Colors.black,
  },
})

export default App

最終 Output:

在此處輸入圖像描述

以下是如何實現 FlatList 項的選擇和取消選擇:

import React, { useState } from 'react';
import {
  SafeAreaView,
  StyleSheet,
  View,
  Text,
  StatusBar,
  FlatList,
  Pressable,
} from 'react-native';


const App = () => {
  const [data, setData] = useState([
    {
      name: 'Foo',
      id: '1',
      isSelected: false,
    },
    {
      name: 'Boo',
      id: '2',
      isSelected: false,
    },
    {
      name: 'Koo',
      id: '3',
      isSelected: false,
    },
    {
      name: 'Poo',
      id: '4',
      isSelected: false,
    },
    {
      name: 'Too',
      id: '5',
      isSelected: false,
    },
    {
      name: 'Qoo',
      id: '6',
      isSelected: false,
    },
  ]);

  const tappedItem = (item) => {
    console.log(item);
    const modifiedList= data.map((element) => {
      if (element.id === item.id) {
        return { ...element, isSelected: !element.isSelected };
      }
      return element;
    });
    setData(modifiedList);
  };

  const renderItem = (item) => {
    return (
      <Pressable onPress={() => tappedItem(item.item)}>
        <View
          style={[
            styles.sectionContainer,
            { backgroundColor: item.item.isSelected ? 'pink' : 'lightgray' },
          ]}>
          <Text style={styles.sectionTitle}>{item.item.name}</Text>
        </View>
      </Pressable>
    );
  };

  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <View style={styles.body}>
          <FlatList
            data={data}
            keyExtractor={(item) => item.id}
            renderItem={renderItem}
            extraData={data}
          />
        </View>
      </SafeAreaView>
    </>
  );
};

const styles = StyleSheet.create({
  body: {
    backgroundColor: 'white',
  },
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
    color: 'black',
  },
});

export default App;

tappedItem()的工作:

/* 
Lets assume we pressed first item in the FlatList, the item that we will be passing 
is: {
      name: 'Foo',
      id: '1',
      isSelected: false,
    }

After that is done most important and also probably the easiest part, 
the modification of the existing state, i.e. toggling the selected property. 

*/
const tappedItem = (item) => {
    console.log(item);
/*
In the following map operation, we iterate through the existing state, i.e. data.
and when we find the matching id, 1 in the case of 
=> {
      name: 'Foo',
      id: '1',
      isSelected: false,
    }

we return the mutated object where we change only the `isSelected` property

You can see this happening here: 
=> if (element.id === item.id) {
        return { ...element, isSelected: !element.isSelected };
   }
in above if statement, we spread the `element` object, toggle the `isSelected` property and return it. 

If the id does not matches then we can simply return the original `element` object without any changes. 

So after that, we will get the modifiedList which will have the `isSelected` toggled as we intend to. 

Then we simply set the data state with that of the newly modified list. 

=> setData(modifiedList);

*/
    const modifiedList= data.map((element) => {
      if (element.id === item.id) {
        return { ...element, isSelected: !element.isSelected };
      }
      return element;
    });
    setData(modifiedList);
  };

/*
this variation of your existing tappedItem function will work fine too, 

just be careful not to mutate the states directly as you did in the original case

=>  data[itemIndex] = newItem [❌]
=> let temp = [...data] 
   temp[itemIndex] = newItem; [✔]
*/


 const tappedItem = (item) => {
    let temp = [...data] //<= create a copy of current state
    const itemIndex = data.findIndex((i) => i.id == item.id);
    const newItem = data[itemIndex];
    newItem.isSelected = !newItem.isSelected;
    temp[itemIndex] = newItem; //<= modify that copy
    setData(temp); //<= use it to set the state.
  };

完整的工作演示: Expo Snack

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM