0

我在 React Native 上有一个非常简单的基于列表的任务管理器: https ://snack.expo.dev/@bradbarnes99/test-dummy-tasky

代码工作得很好,直到我尝试将 react-native-draggable-flatlist 模块适应于此,现在我得到:“文本字符串必须在组件内呈现”

这是来自收到错误的容器的代码。

import React from 'react';
import {
  SafeAreaView,
  StyleSheet,
  Text,
  TextInput,
  View,
  TouchableOpacity,
  StatusBar,
  Alert,
  ScrollView,
} from 'react-native';
import DraggableFlatList from 'react-native-draggable-flatlist';
import { FontAwesome5 } from '@expo/vector-icons';
import AsyncStorage from '@react-native-async-storage/async-storage';
import uuid from 'react-native-uuid';
import BlueButton from '../components/BlueButton';
import Header from '../components/Header';
import Checkbox from '../components/Checkbox';

let anyChecked = false;

export default class MainScreen extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      addTaskValue: '',
      taskers: [],
    };
    this.getIt();
  }

  addTaskTextHandler = (val) => {
    this.setState({ addTaskValue: val });
  };

  addTaskButtonHandler = () => {
    let key = uuid.v4();
    let task = this.state.addTaskValue;
    task = task.trim();
    let order = this.state.taskers.length + 1;
    const taskToAdd = { key, order, title: task, checked: false };
    if (task) {
      this.setState({ taskers: [...this.state.taskers, taskToAdd] });
      this.storeIt();
    } else {
      alert('Enter a task');
    }
    this.setState({ addTaskValue: '' });
  };

  storeIt = async () => {
    const jsonValue = JSON.stringify(this.state.taskers);
    try {
      await AsyncStorage.setItem('taskKey', jsonValue);
    } catch (err) {
      console.log(err);
    }
  };

  onChecked = (key) => {
    const index = this.state.taskers.findIndex(function (o) {
      return o.key === key;
    });
    let tempTaskers = [...this.state.taskers];
    tempTaskers[index].checked =
      tempTaskers[index].checked === true ? false : true;
    console.log(tempTaskers[index].checked);

    this.setState({ taskers: [...tempTaskers] });
    this.storeIt();
    this.anyCheckedTasks();
  };

  anyCheckedTasks = () => {
    let checked = false;
    for (let i = 0; i < this.state.taskers.length; i++) {
      if (this.state.taskers[i].checked === true) {
        anyChecked = true;
        this.forceUpdate();
        return;
      }
    }
    anyChecked = false;
    this.forceUpdate();
    return;
  };

  getIt = async () => {
    try {
      const value = await AsyncStorage.getItem('taskKey');
      if (value != null) {
        this.setState({ taskers: JSON.parse(value) });
      } else {
        this.setState({ taskers: [] });
      }
      this.anyCheckedTasks();
    } catch (err) {
      console.err(err);
    }
  };

  deleteTasksButtonHandler = () => {
    Alert.alert('Warning', 'Delete All Tasks?', [
      {
        text: 'Cancel',
        onPress: () => console.log('Cancel Pressed'),
        style: 'cancel',
      },
      { text: 'OK', onPress: () => this.deleteTasks() },
    ]);
  };

  deleteTasks = async () => {
    this.setState({ taskers: [] });
    await this.storeIt();
    this.anyCheckedTasks();
    this.forceUpdate();
  };

  deleteCompletedTasksButtonHandler = () => {
    Alert.alert('Warning', 'Delete Completed Tasks?', [
      {
        text: 'Cancel',
        onPress: () => console.log('Cancel Pressed'),
        style: 'cancel',
      },
      { text: 'OK', onPress: () => this.deleteCompletedTasks() },
    ]);
  };

  deleteCompletedTasks = async () => {
    const uncheckedTasks = this.state.taskers.filter((task) => {
      return task.checked === false;
    });
    this.setState({ taskers: uncheckedTasks });

    await this.storeIt();
    this.anyCheckedTasks();
    this.forceUpdate();
  };

  DeleteOneTaskButtonHandler = async (key) => {
    const index = this.state.taskers.findIndex(function (o) {
      return o.key === key;
    });
    let tempTasks = this.state.taskers;
    if (index !== -1) tempTasks.splice(index, 1);
    this.setState({ taskers: tempTasks });
    await this.storeIt();
    this.anyCheckedTasks();
    this.forceUpdate();
  };

  renderItem = ({ item, index, drag, isActive }) => {
    return (
      <View style={styles.checkbox}>
        <TouchableOpacity onLongPress={drag}>
                    
          <Checkbox
            key={item.key}
            title={item.title}
            isChecked={item.checked}
            onToggleChange={() => this.onChecked(item.key)}
          />
        </TouchableOpacity>
                  
        <FontAwesome5
          name="times-circle"
          size={24}
          color="#BCE0FD"
          style={styles.deleteTask}
          onPress={() => {
            this.DeleteOneTaskButtonHandler(item.key);
          }}
        />
      </View>
    );
  };

  render() {
    let { title, style } = this.props;
    return (
      <SafeAreaView style={styles.container}>
        <StatusBar barStyle="dark-content" />
        <Header instructions="You are the Task Master!" />
        <View style={styles.body}>
          <Text style={styles.addTask}>Add Task</Text>
          <View style={styles.addTaskRow}>
            <TextInput
              style={styles.input}
              value={this.state.addTaskValue}
              onChangeText={this.addTaskTextHandler}
            />
            <TouchableOpacity
              style={[styles.addButton, style]}
              onPress={this.addTaskButtonHandler}>
              <Text style={styles.addButtonText}>Add</Text>
            </TouchableOpacity>
          </View>
          <ScrollView>
            {this.state.taskers.length > 0 && (
              <>
                <DraggableFlatList
                  data={this.state.taskers}
                  renderItem={this.renderItem}
                  keyExtractor={(item, index) => item.key}
                  onDragEnd={({ data }) => this.setState({ data })}
                />
              </>
            )}

            {this.state.taskers.length > 0 && (
              <View style={{ margin: 25 }}>
                <BlueButton
                  title="Delete All Tasks"
                  style={
                    anyChecked
                      ? { width: '100%', marginBottom: 0 }
                      : { width: '100%', marginBottom: 225 }
                  }
                  onPress={this.deleteTasksButtonHandler}
                />
              </View>
            )}

            {anyChecked && (
              <View style={{ margin: 25 }}>
                <BlueButton
                  title="Delete Completed Tasks"
                  style={{ width: '100%', marginTop: -25, marginBottom: 225 }}
                  onPress={this.deleteCompletedTasksButtonHandler}
                />
              </View>
            )}
          </ScrollView>
        </View>
      </SafeAreaView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
  body: {
    margin: 25,
  },
  addTask: {
    color: '#2699FB',
    marginBottom: 10,
  },
  addTaskRow: {
    flexDirection: 'row',
    marginBottom: 25,
  },
  input: {
    borderColor: '#2699FB',
    borderWidth: 2,
    borderStyle: 'solid',
    paddingTop: 15,
    paddingBottom: 15,
    marginBottom: 30,
    paddingLeft: 10,
    paddingRight: 10,
    width: '80%',
    marginRight: 10,
  },
  addButton: {
    backgroundColor: '#BCE0FD',
    padding: 15,
    borderRadius: 4,
    height: '63%',
  },
  addButtonText: {
    color: '#2697FB',
    fontWeight: 'bold',
    textAlign: 'center',
    fontSize: 16,
    textTransform: 'uppercase',
  },
  checkbox: {
    flex: 1,
    flexDirection: 'row',
    marginBottom: 15,
  },
  deleteTask: {
    marginLeft: 'auto',
    alignSelf: 'center',
    transform: 'translateY: -80px',
  },
});

这是 Checkbox 组件中的代码,以防出现触发错误的情况...

import React from 'react';
import {View, Text, Image, StyleSheet, TouchableOpacity} from 'react-native';

const imgCheck = require('../assets/check.png');

export default class Checkbox extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isComplete: props.isChecked,
        };
    }

    toggleCheck() {
        let status = this.state.isComplete;
        this.setState({
            isComplete: !status,
        });

        // Notify any listeners of the state change
        if (this.props.onToggleChange) {
            this.props.onToggleChange(this.props.key, this.props.item, !status);
        }
    }

    render() {
        return (
            <View style={styles.container}>
                <TouchableOpacity onPress={() => this.toggleCheck()}>
                    <View style={this.state.isComplete ? styles.boxChecked : styles.box}>
                        {this.state.isComplete && (
                            <Image source={imgCheck} style={styles.check} />
                        )}
                    </View>
                </TouchableOpacity>
                <Text
                    style={this.state.isComplete ? styles.titleComplete : styles.title}>
                    {this.props.title}
                </Text>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flexDirection: 'row',
        alignItems: 'center',
        padding: 5,
        backgroundColor: "white",
    },
    box: {
        borderColor: '#2699FB',
        borderWidth: 2,
        borderStyle: 'solid',
        padding: 3,
        width: 30,
        height: 30,
        justifyContent: 'center',
        alignItems: 'center',
    },
    boxChecked: {
        borderColor: '#2699FB',
        borderWidth: 2,
        borderStyle: 'solid',
        padding: 3,
        width: 30,
        height: 30,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#2699FB',
    },
    check: {
        width: 24,
        height: 24,
    },
    title: {
        color: '#2699FB',
        fontWeight: 'bold',
        marginLeft: 15,
        fontSize: 18,
        maxWidth: '82%'
    },
    titleComplete: {
        color: 'gray',
        marginLeft: 15,
        fontSize: 18,
        maxWidth: '82%'
    },
});

我不知所措。我在 MainScreen.js 中删除了我的所有评论,以防万一引起问题。

你们中的任何人都知道为什么我会收到此错误吗?

我将上面的链接包含到我的 expo.dev 小吃的所有代码中。

提前致谢!

4

0 回答 0