Как обновить атрибут элемента FlatList? - PullRequest
0 голосов
/ 26 октября 2019

Я запрограммировал приложение для Android, которое состоит из TextInput, Button и FlatList. С каждым именем, записанным в TextInput, в плоском списке будет элемент. Заголовок элемента будет содержимым TextInput, а рядом с элементом списка будут две кнопки и текст. Кнопка предназначена для увеличения числа, которое текст отображает на 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 для кнопок увеличения и уменьшения, чтобы они работали?

Ответы [ 2 ]

0 голосов
/ 26 октября 2019

Ответ Макса - это один из способов реализации, но производительность не очень хорошая, каждый раз, когда дочернее обновление обновляется, все представление отображается снова. Вот мое решение:
во-первых, в родительском компоненте зарегистрируйте событие, которое будет получать дочернее уведомление об обновлении.

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 в один компонент и позволить емуобновите значение

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>       

    );
   }

Надеюсь, это поможет вам.

0 голосов
/ 26 октября 2019

В 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
                  })
          })}

Что происходит здесь, мы создаем новый файл task_array из старого, используя . map () метод массива, оставляющий нетронутым каждый элемент, кроме одного, который был нажат - который мы определяем путем сравнения индексов. В этом случае мы увеличиваем его счетчик и назначаем новое значение для task_array, используя this.setState

...