【问题标题】:How to pass down item from a flatlist to a grandchild?如何将项目从平面列表传递给孙子?
【发布时间】:2019-11-05 21:24:01
【问题描述】:

我有一个项目清单。当我将项目传递给 renderItem 组件时,一切正常。然后,当我将完全相同的项目传递给我的组件中负责渲染项目的子项时,就会出现问题。

通常它工作得非常好,但如果有多个列表项并且它上面的一个被删除,它会失去适当的功能并且变得非常错误。我认为问题在于,无论出于何种原因,一个项目假定了前一个项目的索引,孙子仍然认为它是那个项目,而不是移动到该索引中的另一个项目。

我的列表:

<FlatList
            data={this.props.items}
            extraData={this.props.items}
            keyExtractor={(item, index) => index.toString()}
            renderItem={({ item }) => {
              return (
                <TodoItem
                  todoItem={item}
                />
              );
            }}
          />

然后在 TodoItem 中,这就是我将项目传递给孙子的方式:

class TodoItem extends Component {
  render() {
    const todoItem = this.props.todoItem;

    return (
        <View>
          <ItemSwipeRow
            item={todoItem}
            completeItem={this.props.deleteTodo}
          >

然后在 itemSwipeRow 这就是我接收道具的方式

import React, { Component } from 'react';
import { Animated, StyleSheet, View } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
import Swipeable from 'react-native-gesture-handler/Swipeable';
import { Ionicons, MaterialCommunityIcons } from '@expo/vector-icons';
import { connect } from 'react-redux';
import { openNotesModal, openDateModal } from '../actions';

const AnimatedIcon = Animated.createAnimatedComponent(Ionicons);

class ItemSwipeRow extends Component {
  constructor(props) {
    super(props);
    this.item = props.item;
  }

  renderLeftActions = (progress, dragX) => {
    const trans = dragX.interpolate({
      inputRange: [0, 50, 100, 101],
      outputRange: [-20, 0, 0, 1],
    });
    return (
      <RectButton style={styles.leftAction}>
        <AnimatedIcon
          name='md-checkmark'
          color='#28313b'
          size={45}
          style={[
            styles.actionText,
            {
              transform: [{ translateX: trans }],
            },
          ]}
        />
      </RectButton>
    );
  };

  renderRightAction = (action, name, color, x, progress) => {
    const trans = progress.interpolate({
      inputRange: [0, 1],
      outputRange: [x, 0],
    });
    const pressHandler = () => {
      action(this.item);
    };
    return (
      <Animated.View style={{ flex: 1, transform: [{ translateX: trans }] }}>
        <RectButton
          style={[styles.rightAction, { backgroundColor: color }]}
          onPress={pressHandler}
        >
          <MaterialCommunityIcons
            name={name}
            size={35}
            color='#28313b'
          />
        </RectButton>
      </Animated.View>
    );
  };

  renderRightActions = progress => (
    <View style={styles.rightSwipeButtons}>
      {this.renderRightAction(
        this.props.openDateModal, 'calendar', '#B8B8F3', 192, progress
      )}
      {this.renderRightAction(
        this.props.openNotesModal, 'pencil', '#F0A202', 128, progress
      )}
      {this.renderRightAction(
        this.props.openDateModal, 'bell', '#db5461', 64, progress
      )}
    </View>
  );

  updateRef = ref => {
    this.currItem = ref;
  };
  close = () => {
    if (this.currItem !== null) { this.currItem.close(); }
  };

  onSwipeableLeftOpen = () => {
    this.props.completeItem();
    this.close();
  }

  onSwipeableRightWillOpen = () => {
    console.log(this.item.text); //tried passing in item here but didn't 
  } //work, instead of console logging on call it did every item @ start
    // then none when it was suppose to log it.
  render() {
    const { children } = this.props;
    const { item } = this.props;
    return (
      <Swipeable
        ref={this.updateRef}
        friction={2}
        leftThreshold={70}
        rightThreshold={40}
        renderLeftActions={this.renderLeftActions}
        renderRightActions={this.renderRightActions}
        onSwipeableLeftOpen={this.onSwipeableLeftOpen}
        onSwipeableRightWillOpen={this.onSwipeableRightWillOpen}
      >
        {children}
      </Swipeable>
    );
  }
}

const styles = StyleSheet.create({
  leftAction: {
    flex: 1,
    backgroundColor: '#82ff9e',
    justifyContent: 'center',
  },
  rightAction: {
    alignItems: 'center',
    flex: 1,
    justifyContent: 'center',
  },
  rightSwipeButtons: {
    width: 192,
    flexDirection: 'row'
  }
});


export default connect(null, { openNotesModal, openDateModal })(ItemSwipeRow);

我的控制台日志证明并不总是呈现正确的项目。该项目的删除工作正常,但是如果一个项目被删除并且它下面有东西,那么它下面的项目假定它是刚刚删除的项目。

对此的任何帮助将不胜感激,如果需要,我可以提供更多代码。

删除项目的代码:

action that's sent on left swipe–

export const removeTodo = (item) => {
  return {
    type: REMOVE_TODO,
    id: item.id
  };
};

reducer action goes to–

case REMOVE_TODO: {
      const newList = state.todos.filter(item => item.id !== action.id);
      for (let i = 0, newId = 0; i < newList.length; i++, newId++) {
        newList[i].id = newId;
      }
      return {
      ...state,
      todos: newList
      };
    }

【问题讨论】:

  • 您的数据中没有自然键吗?如果是,您可以将其用作平面列表中的键吗?
  • 每个项目都有一个id,你是说我应该把它作为索引吗?
  • 是的,这样会更好,keyExtractor={(item) => item.id}
  • 这也可以解决您遇到的问题。
  • 好的没问题,这样还是不错的。

标签: reactjs react-native


【解决方案1】:

您可以使用解构赋值来复制对象,而不是引用同一个对象:

const { todoItem } = this.props

进一步阅读:https://medium.com/@junshengpierre/javascript-primitive-values-object-references-361cfc1cbfb0

【讨论】:

  • 所以我把那行放在渲染方法中,然后将项目传递给辅助方法。但这并没有按预期工作,并且正在记录整个列表而不是单个项目?
  • 当我以我最初拥有的状态调用该方法时,只有控制台在滑动时记录正确的项目(辅助方法的设计目的)。当我用解构调用它时,它会直接在渲染中记录它,然后当我滑动它时什么也没有。
  • 听起来你传递了一个错误的函数和变异的状态。请提供完整的 3 个组件。
  • 我添加了整个 itemSwipe 组件。我不认为其余代码有什么不同,但如果您认为问题不在我添加的代码中,我可以添加它。
  • 删除操作功能是什么样的?
猜你喜欢
  • 2021-09-17
  • 2015-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-18
  • 2019-03-04
  • 2021-12-28
  • 1970-01-01
相关资源
最近更新 更多