如何在React Native中编辑FlatList中的项目

3
我这周刚开始学习 React Native,通过观看一些漫长的 YouTube 教程后,我决定创建一个待办事项应用程序,在该应用程序中,用户可以添加、删除和编辑待办事项列表。目前我的代码只能添加和删除,但是我想知道如何在我的项目中添加编辑功能。我不知道如何让它工作,如果有人能帮我提供一些想法,那就太棒了。
这是我项目的 Codesandbox 链接:https://codesandbox.io/s/vigilant-williamson-4zv7s?file=/src/App.js 如果您有任何问题,请在评论中让我知道。

请在您的代码中包含 https://codesandbox.io 的链接,以展示您的工作示例。 - macborowy
通常情况下,您需要一个编辑回调处理程序,它接受要编辑的数据元素的索引或ID(以切换某些编辑视图),编辑模式视图(即某些输入)和保存编辑处理程序以在状态中更新该元素。请尝试在您的问题中包含一个最小、完整和可重现的代码示例,如果可能的话,请包含一个运行中的codesandbox,并尽可能清楚地说明任何问题和期望的结果。祝你好运。 - Drew Reese
@DrewReese,我刚刚添加了沙盒,真心希望它有所帮助。如果有任何问题,请告诉我。 - Juan Martin Zabala
@macborowy,我刚刚添加了沙盒,真心希望它能有所帮助。如果有任何问题,请告诉我。 - Juan Martin Zabala
1个回答

1
要使其工作,您需要添加一个新的编辑处理程序,类似于pressHandler,但是编辑条目而不是删除它。可能的编辑处理程序可能如下所示:
const editHandler = (todoKey, newText) => {
  const newTodos = [...todos];
  const index = newTodos.findIndex(todos => todos.key === todoKey);
  newTodos[index] = Object.assign(newTodos[index], { value: newText });

  setTodos(newTodos);
};

它将编辑过的元素移动到列表末尾。如果需要,您可以自行更改此行为。
然后,您需要将处理程序传递给 <TodoItem />
<TodoItem
  key={item.key}
  todoKey={item.key}
  title={item.value}
  editHandler={editHandler}
  pressHandler={pressHandler}
/>

你不需要绑定函数组件的函数,但是你需要为在map()中渲染的每个组件提供一个key属性。我已经改变了它,并提供了一个todoKey属性,我后来在<TodoItem />中使用。
<TodoItem />中,你可以像在<AddTodo />中创建新的todo时一样使用类似的逻辑来修改todo文本。当isEditingtrue时,我使用条件渲染来渲染<TextInput />,当它不是这样时则使用<Text />
{isEditing 
  ? <TextInput value={text} onChangeText={setText} style={styles.itemText} />
  : <Text style={styles.itemText}>{props.title}</Text>
}

同样地,我有条件地渲染 保存编辑 按钮。
完整的 <TodoItem /> 组件:
const TodoItem = props => {
  const [text, setText] = useState("");
  const [isEditing, setEdit] = useState(false);

  const handleEdit = () => {
    props.editHandler(props.todoKey, text);
    setText("");
    setEdit(false);
  };

  return (
    <View style={styles.items}>
      <View style={styles.itemContainer}>
        {isEditing 
          ? <TextInput value={text} onChangeText={setText} style={styles.itemText} />
          : <Text style={styles.itemText}>{props.title}</Text>
        }
        <View style={styles.btnContainer}>
          <Buttons title="Delete" onPress={() => props.pressHandler(props.todoKey)} style={styles.itemBtn} />
          {isEditing 
            ? <Buttons title="Save" onPress={handleEdit} style={styles.editBtn} />
            : <Buttons title="Edit" onPress={() => setEdit(true)} style={styles.editBtn} />
          }
        </View>
      </View>
    </View>
  );
};

const styles = /* ... */

以下是一个包含代码的Codesandbox: https://codesandbox.io/s/public-edit-todo-item-bsc9p


编辑 1

如果您想在编辑时加载当前的 TODO 标题而不是首先清除它,请更改 <TodoItem />

  • props.title 设置为 text 的初始值
  • handleEdit 中删除 setText("") - 它不再需要
const TodoItem = props => {
  const [text, setText] = useState(props.title);
  const [isEditing, setEdit] = useState(false);

  const handleEdit = () => {
    props.editHandler(props.todoKey, text);
    setEdit(false);
  };

  return (
    {/* stays the same */}
  )
}

?让您有条件地渲染元素,因此如果isEditingtrue,React将呈现<TextInput /><Text />,否则不呈现。 - macborowy
1
@JuanMartinZabala 你说得对,将一个项添加到数组的末尾是不必要的。我之所以这样做是因为我无法让状态更新正常工作。我犯了一个错误,试图直接更新React中被禁止的状态。我已经更新了答案,加上了正确的代码。 - macborowy
嘿,macborowny!基本上为了解决这个问题,你调用了所有的todos元素,使用 [...todos] 这样的方式,然后为了定位要编辑的选定元素,你添加了 .findIndex(todos => todos.key === todoKey),并且你给索引赋了一个新值,最终使用 setTodos(newTodos) 应用到原始数组中,对吗? - Juan Martin Zabala
@JuanMartinZabala 是的,你说得对。[...todos]会创建一个新数组,其中包含前一个数组中的所有元素。React在重新渲染期间使用浅比较,这意味着它将查看数组是否改变本身(例如:是否有新元素),而不是数组元素是否改变(例如:对象属性是否改变)。 - macborowy
让我知道如果你需要更多的解释 - Juan Martin Zabala
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接