【问题标题】:UseEffect dependency array keeps running even state does not changeUseEffect 依赖数组保持运行状态不改变
【发布时间】:2023-01-26 20:26:18
【问题描述】:

我有一个 useEffect,它一直在无限循环中运行,即使我在依赖数组中使用的状态没有改变(或者我是否遗漏了一些关于我的任务状态的信息,它正在某处改变?) useEffect 用于从 Firestore 查询和检索数据,代码如下:

import { StyleSheet, View, FlatList, Animated } from 'react-native'
import React, {useEffect, useState} from 'react'
import { Subheading, Divider, Text, Modal, Button, Portal, TextInput} from 'react-native-paper';
import Swipeable from 'react-native-gesture-handler/Swipeable'
import { TouchableOpacity } from 'react-native-gesture-handler';
import { collection, where, query, getDocs, addDoc, deleteDoc} from 'firebase/firestore';
import { db} from '../../firebase/firebase'
import firebase from 'firebase/compat/app';
import uuid from "react-native-uuid";


export default function TaskComponent({route}) {
  const item = route.params.item;
  const containerStyle = {backgroundColor: 'white', padding: 60, margin: 10};
  const [tasks, setTasks] = useState({});
  const [textInput, setTextInput] = useState({name: "", description: ""});
  let userID = `${firebase.auth().currentUser.uid};`
  const filteredTasks = [];


  useEffect(() => {
    const getFilterTasks = async() => {
      const q = query(collection(db, 'allTasks'), where('userID', '==', userID), where('categoryID', '==', item.id))
      const querySnapshot = await getDocs(q);
      querySnapshot.forEach((doc) => {
        filteredTasks.push(doc.data())
      })
      setTasks(filteredTasks)
    }

    getFilterTasks();

  }, [tasks])


  const handleChange = (name, value) => {
    setTextInput({
      ...textInput,
      [name]: value,
    });
  };


  const showModal = () => {
    setVisible(true);
  }


  const hideModal = () => {
    setVisible(false);
  }


  const addTask = (textInput) => {
    setTasks((prevState) => {
      return [
        {
          userID: userID, 
          categoryID: item.id, 
          name: textInput.name, 
          description: textInput.description, 
          id: uuid.v1()
        },
        ...prevState
      ];
    })

    addToFirebase();

    hideModal();
  }


  const deleteItem = (item) => {
    setTasks((prevState) => {
      return prevState.filter(task => task.id != item.id)
    })
  }

  const addToFirebase = async() => {
      await addDoc(collection(db, 'allTasks'), {
        userID: userID, 
        categoryID: item.id, 
        name: textInput.name, 
        description: textInput.description, 
        id: uuid.v1()
      });
  }


  const DataComponent = (item) => {
    const rightSwipe = (progress, dragX) => {
      const scale = dragX.interpolate({
        inputRange: [-100, 0],
        outputRange: [1, 0],
        extrapolate: 'clamp'
      });

      return(
        <TouchableOpacity activeOpacity={0.8} onPress={() => deleteItem(item)}>
          <View>
            <Animated.Text>Delete</Animated.Text>
          </View>
        </TouchableOpacity>
      )
    }

    return (
      <TouchableOpacity>
      <Swipeable renderRightActions={rightSwipe}>
        <View>
        <View>
          <Text>Name:</Text>
          <Text> {item.name}</Text>
        </View>
        <View>
          <Text>Date:</Text>
          <Text> {item.date}</Text>
        </View>
          <Text>Description:</Text>
          <Text>{item.description}</Text>
        </View>
      </Swipeable>
      </TouchableOpacity>
    )
  }

  return (
    <View>
      <Subheading>Your {item.name} tasks:</Subheading>
      <View>
          <FlatList
          keyExtractor={(item) => item.id}
          data={tasks}
          renderItem={ ({item}) => (
            <DataComponent {...item}/>
            )}
            />
        </View>

        <View>
        <Button mode="contained" uppercase={false} onPress={showModal}>
          Add a task
        </Button>
      </View>

      <Portal>
        <Modal visible={visible} onDismiss={hideModal} contentContainerStyle={containerStyle}>
          <Text>Name your task: </Text>
          <TextInput placeholder="Enter task name" value={textInput.name} onChangeText={(text) => handleChange('name', text)} name="name"/>
          
          <Text>Enter description:</Text>
          <TextInput multiline placeholder="Enter description" value={textInput.description} onChangeText={(text) => handleChange('description', text)}  name="description"/>

          <Button mode="contained" uppercase={false} onPress={() => addTask(textInput)}>
            Add
          </Button>
        </Modal>
      </Portal>
    </View>
  )
}

我也试过只使用一个空的依赖数组,但是每次我想看到正确的数据时我都必须刷新代码。

【问题讨论】:

    标签: javascript firebase react-native google-cloud-firestore react-hooks


    【解决方案1】:

    只需从触发器数组中删除tasks

    保留一个空数组,这样 useEffect 只会在挂载时被调用。

    
      useEffect(() => {
        const getFilterTasks = async() => {
        const q = query(collection(db, 'allTasks'), where('userID', '==', userID), where('categoryID', '==', item.id))
        const querySnapshot = await getDocs(q);
        querySnapshot.forEach((doc) => {
          filteredTasks.push(doc.data())
        })
        setTasks(filteredTasks)
      }
    
      getFilterTasks();
    
      }, [])
    
    

    【讨论】:

    • 但是我需要在每次任务状态更改时检查运行该代码,你有什么建议我可以把我的 setTasks(filteredTasks) 放在哪里或者如何处理它?
    【解决方案2】:

    我知道我迟到了,但在 useEffect 中,你正在调用 getFilterTasks(),它也在调用 setTasks(filteredTasks),这基本上再次更改了你的 tasks 对象,因此再次触发了 useEffect。这就是无限循环的原因。

    当您添加、编辑或删除任务时,您在这里想要的不是 useEffect,而是在操作完成后调用以更新任务的可重用函数。 (一个选项是在 useEffect 之外获取 getFilterTasks 函数,并在 await addDoc(collection(db, 'allTasks'), {...}) 之后在 const addToFirebase 函数内调用它)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-14
      • 2022-01-11
      • 1970-01-01
      • 2023-03-07
      • 2021-01-08
      • 2019-08-09
      • 1970-01-01
      • 2022-07-05
      相关资源
      最近更新 更多