如何更新 FlatList 项目的属性?

Posted

技术标签:

【中文标题】如何更新 FlatList 项目的属性?【英文标题】:How to update the attribute of an item of a FlatList? 【发布时间】:2020-02-22 05:55:52 【问题描述】:

我编写了一个由 TextInput、Button 和 FlatList 组成的 android 应用程序。使用 TextInput 中写入的每个名称,平面列表中都会有一个项目。 Item 标题将是 TextInput 内容,列表项旁边将有两个按钮和一个文本。一个按钮用于将 Text 显示的数字增加 1,另一个用于减少。这是我的代码:

import React, Component from 'react';
import 
  View,
  Text,
  TextInput,
  FlatList,
  TouchableOpacity,

 from 'react-native';
import  ListItem, SearchBar from 'react-native-elements';


class App extends Component 
  constructor(props) 
    super(props);
    this.state = 
      task: "",
      task_array: [],


    ;
  

  ChangeText = (some_task) => 
    this.setState(task: some_task);
  ;
  pushAdd = () => 
    let contact = 
      name: this.state.task,
      counter: 0,
    ;
    this.setState(task_array: [...this.state.task_array, contact]);
  ;








  renderListItem = (item) => 
   return(
     <View style=flexDirection: 'row'>
     <ListItem title=item.name style=width:'75%', marginLeft:20></ListItem>
     <View style=flexDirection:'row'>
         <TouchableOpacity style= backgroundColor: 'blueviolet', height: 20, width: 20, borderRadius: 50 onPress=()=> item=name:item.name, counter:item.counter + 1><Text>+</Text></TouchableOpacity>
         <Text>item.counter</Text>
  //main problem       <TouchableOpacity style= backgroundColor: 'blueviolet', height: 20, width: 20, borderRadius: 50  onPress=() => item =  name: item.name, counter: item.counter - 1 ><Text>-</Text></TouchableOpacity>

     </View>

     </View>

   );
  ;


render() 
  return(
    <View style= backgroundColor: 'mediumturquoise', width:'100%', height:'100%'>
    <FlatList 
      data = this.state.task_array
      renderItem = this.renderListItem
      keyExtractor = (item) => item.name>
    </FlatList>
    <View style = flexDirection : 'row', alignContent:'center', alignItems:'center'>
        <TextInput onChangeText=this.ChangeText style= backgroundColor: 'burlywood', height:50, width:'75%', borderRadius:30, marginBottom:20, marginLeft:20, marginRight:20></TextInput>
        <TouchableOpacity style= backgroundColor: 'chocolate', height:40, width:50, borderRadius:10, marginBottom:20 onPress=this.pushAdd></TouchableOpacity>
    </View>
    </View>
  );
  
;

export default App;

我用评论“主要问题”指出了有问题的行。增加和减少按钮不起作用,当我在应用程序中按下它们时,文本中的数字保持不变。我应该对我的增加和减少按钮的 onPress 方法进行什么更改才能让它们工作?

【问题讨论】:

【参考方案1】:

在 React 中,您不能直接操作数据(就像您在 +/- 按钮的 onPress 方法中所做的那样)。这不会产生任何影响,相反,您需要使用 setState 适当地更改状态

最快的解决办法就是改变

// this
renderListItem = (item) => 
// to this
renderListItem = (item, index) => 

知道渲染项目的索引。然后,将这些项目内的递增/递减按钮的onPress 方法更改为使用setState

// from this
onPress=()=> item=name:item.name, counter:item.counter + 1
// to this
onPress=() =>
          this.setState(
            task_array: this.state.task_array
              .map((item, itemIndex) =>
                itemIndex !== index
                  ? item
                  : 
                    ...item,
                    counter: item.counter + 1
                  )
          )

这里发生的是我们使用数组的.map() 方法从旧的task_array 创建一个新的task_array,除了被点击的一个元素之外,每个元素都保持不变——我们通过比较索引来定义它。在这种情况下,我们增加它的计数器并使用 this.setState 为 task_array 分配新值

【讨论】:

嗨 Max 你能看看我的问题吗。***.com/questions/65769926/…【参考方案2】:

Max的回答是一种实现方式,但是性能不好,每次child更新,all view都会重新渲染一遍。 这是我的解决方案: 首先,在父组件中注册一个事件,接收子更新通知。

class App extends Component 
  constructor(props) 
    super(props);
    this.state = 
      task: "",
      task_array: [],
    ;
  

// register the event,
componentDidMount() 
    DeviceEventEmitter.addListener('itemUpdate', this.updateData)
  

  componentWillUnmount () 
    DeviceEventEmitter.removeListener('ModalVisible', this.updateData)
  
  updateData = (params) => 
      let copyTaskArray = ...this.state.task_array
      copyTaskArray[params.index].counter = params.counter
      this.state.task_array = copyTaskArray
  

那么我们应该将 FlatList Item 移动到单个 Component 中,并让它更新值

import React,Component from 'react';
import  View, TouchableOpacity,DeviceEventEmitter from 'react-native';
export default class Item extends Component
    constructor(props) 
      super(props);
      this.state = 
        counter:this.props.item.counter
      ;
    

    plus = () => 
      let oldCounter = this.state.counter;
      let newCounter = oldCounter +1;
      this.setState(
         counter: newCounter
      )
      // notify the parent
      DeviceEventEmitter.emit("itemUpdate",index:this.props.index,counter:this.state.counter)
    

    reduce = () => 
       // the same with plus, only oldCounter -1
    

    render() 
      return(
       <View key=this.props.index style=flexDirection: 'row'>
       <ListItem title=this.props.item.name style=width:'75%', marginLeft:20></ListItem>
       <View style=flexDirection:'row'>
           <TouchableOpacity style= backgroundColor: 'blueviolet', height: 20, width: 20, borderRadius: 50 onPress=this.plus>
           <Text>+</Text>
           </TouchableOpacity>
           <Text>his.props.item.counter</Text>
     <TouchableOpacity style= backgroundColor: 'blueviolet', height: 20, width: 20, borderRadius: 50  onPress=this.reduce>
      <Text>-</Text>
     </TouchableOpacity>
       </View>
       </View>
    ) 
  

在这种情况下,当项目在屏幕上滚动并重新创建时,该值仍然存在。 最后,我们应该更改父项的 renderListItem 方法。

renderListItem = (item, index) => 
    return(
     <Item index=index item=item ></Item>       

    );
   

希望对你有帮助。

【讨论】:

这在很多层面上都是错误的。 1. this.state.task_array = copyTaskArray 直接违反 React 准则,会立即导致 bug。 2. 依赖一些 EventEmitter for ui 不是 React 的做法。你不需要它。您可能最终会使用不支持它的平台,例如视窗。 3. 将 props 复制到 state 是违反 React 准则的。 4.你的上层状态是无用的,你将无法从中渲染任何东西,例如尝试在 FlatList 旁边显示一个文本,其中包含 task_array 中所有项目的计数器总和,看看会发生什么 @Max,谢谢,这是解决问题的一种方法。根据不同的情况采取不同的解决方案。但一定要小心使用

以上是关于如何更新 FlatList 项目的属性?的主要内容,如果未能解决你的问题,请参考以下文章

如果更新数据,如何更新FlatList

反应原生 Flatlist 导航

VirtualizedList:您有一个更新缓慢的大列表 - React Native FlatList

如何在 React Native 中包装 Flatlist 项目

如何将道具从 FlatList 项目传递给 Modal?

保存页面时重新呈现 FlatList 项目