Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs axios期间更改路由导致useEffect挂钩内存泄漏_Reactjs_React Hooks - Fatal编程技术网

Reactjs axios期间更改路由导致useEffect挂钩内存泄漏

Reactjs axios期间更改路由导致useEffect挂钩内存泄漏,reactjs,react-hooks,Reactjs,React Hooks,当我点击一个选项卡,数据表正在加载(在axios调用期间),并且在加载完成(axios返回数据)之前,我点击了一个链接,该链接将我带到同一网站内的另一条路线,就会发生此错误 代码如下: useEffect(() => { if (reloadTable) { setReloadTable(false); // Forces this useEffect to be called once } else { let dataSelected = []; con

当我点击一个选项卡,数据表正在加载(在axios调用期间),并且在加载完成(axios返回数据)之前,我点击了一个链接,该链接将我带到同一网站内的另一条路线,就会发生此错误

代码如下:

useEffect(() => {
  if (reloadTable) {
    setReloadTable(false); // Forces this useEffect to be called once
  } else {
    let dataSelected = [];
    const options = {
      keyName: process.env.REACT_APP_KEY_NAME,
      keyValue: process.env.REACT_APP_KEY_VALUE
    }
    if(tab === "Instructors"){
      setIsLoadingInstructorsTable(true);
      axios.post(`https://example.com/school/api/Instructors/GetAllInstructors`, options)
      .then(data => {
          dataSelected = data.data.instructors.map(instructorData => {
            return {id: instructorData.id, name: instructorData.name, assistants: instructorData.assistants, students: instructorData.students, hours: instructorData.hours, classes: instructorData.classes};
          });
          setTableInstructorData(dataSelected);
          setInstructorDisplayTableData(dataSelected);
          setListOfBooks(data.data.books);
          setListOfClasses(data.data.classes);
          setListOfcurriculums(data.data.datacurriculums);
          setListOfMeetings(data.data.);
          setIsLoadingInstructorsTable(false);
          setSearchTerm("");
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingInstructorsTable(false);
          setSearchTerm("");
        }
      );
    }
    if(tab === "Assistants"){
      setIsLoadingAssistantsTable(true);
      axios.post(`https://example.com/school/api/Assistants/GetAllAssistants`, options)
      .then(data => {
          dataSelected = data.data.assistants.map(assistantData => {
            return {id: assistantData.id, name: assistantData.name, hours: assistantData.hours};
          });
          setTableAssistantsData(dataSelected);
          setAssistantsDisplayTableData(dataSelected);
          setListOfBooks(data.data.books);
          setListOfClasses(data.data.classes);
          setListOfcurriculums(data.data.datacurriculums);
          setListOfMeetings(data.data.);
          setIsLoadingAssistantsTable(false);
          setSearchTerm("");
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingAssistantsTable(false);
          setSearchTerm("");
        }
      );
    }
    if(tab === "Students"){
      setIsLoadingStudentsTable(true);
      axios.post(`https://example.com/school/api/Students/GetAllStudents`, options)
      .then(data => {
          dataSelected = data.data.students.map(studentData => {
            return {id: assistantData.id, name: assistantData.name, books: assistantData.books, classes: assistantData.classes};
          });
          setTableStudentsData(dataSelected);
          setStudentsDisplayTableData(dataSelected);
          setListOfBooks(data.data.books);
          setListOfClasses(data.data.classes);
          setListOfcurriculums(data.data.datacurriculums);
          setListOfMeetings(data.data.);
          setIsLoadingStudentsTable(false);
          setSearchTerm("");
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingStudentsTable(false);
          setSearchTerm("");
        }
      );
    }
  }
}, [tab, reloadTable]);
下面是我看到的错误:

我试图按照错误提示查找“useEffect清理函数”,但找不到任何有用的方法来解决此代码的问题。有人有什么想法吗


编辑:正在尝试useRef()

在这里找到一个解决方案后>

我试着用这个代码实现它

import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';

const isMounted = useRef(null);
useEffect(() => {
  if (reloadTable) {
    setReloadTable(false); // Forces this useEffect to be called once
  } else {
    let dataSelected = [];
    const options = {
      keyName: process.env.REACT_APP_KEY_NAME,
      keyValue: process.env.REACT_APP_KEY_VALUE
    }
    if(tab === "instructors"){
      setIsLoadingInstructorsTable(true);
      isMounted.current = true;
      axios.post(`https://example.com/school/api/Instructors/GetAllInstructors`, options)
      .then(data => {
          dataSelected = data.data.instructors.map(instructorData => {
            return {id: instructorData.id, name: instructorData.name, assistants: instructorData.assistants, students: instructorData.students, hours: instructorData.hours, classes: instructorData.classes};
          });
          setTableInstructorData(dataSelected);
          setInstructorDisplayTableData(dataSelected);
          setListOfBooks(data.data.books);
          setListOfClasses(data.data.classes);
          setListOfcurriculums(data.data.datacurriculums);
          setListOfMeetings(data.data.);
          setIsLoadingInstructorsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingInstructorsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      ).finally(() => {
        if (isMounted.current) {
          setIsLoadingInstructorsTable(false);
        }
      });
    }
    if(tab === "assistants"){
      setIsLoadingAssistantsTable(true);
      isMounted.current = true;
      axios.post(`https://example.com/school/api/Assistants/GetAllAssistants`, options)
      .then(data => {
          dataSelected = data.data.assistants.map(assistantData => {
            return {id: assistantData.id, name: assistantData.name, hours: assistantData.hours};
          });
          setTableAssistantsData(dataSelected);
          setAssistantsDisplayTableData(dataSelected);
          setListOfBooks(data.data.books);
          setListOfClasses(data.data.classes);
          setListOfcurriculums(data.data.datacurriculums);
          setListOfMeetings(data.data.);
          setIsLoadingAssistantsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingAssistantsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      ).finally(() => {
        if (isMounted.current) {
          setIsLoadingAssistantsTable(false);
        }
      });
    }
    if(tab === "students"){
      setIsLoadingStudentsTable(true);
      isMounted.current = true;
      axios.post(`https://example.com/school/api/Students/GetAllStudents`, options)
      .then(data => {
          dataSelected = data.data.students.map(studentData => {
            return {id: assistantData.id, name: assistantData.name, books: assistantData.books, classes: assistantData.classes};
          });
          setTableStudentsData(dataSelected);
          setStudentsDisplayTableData(dataSelected);
          setListOfBooks(data.data.books);
          setListOfClasses(data.data.classes);
          setListOfcurriculums(data.data.datacurriculums);
          setListOfMeetings(data.data.);
          setIsLoadingStudentsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingStudentsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      ).finally(() => {
        if (isMounted.current) {
          setIsLoadingStudentsTable(false);
        }
      });
    }
  }
}, [tab, reloadTable]);

但是错误仍然会发生

您可以使用一个ref来指示在执行所有状态更新之前是否卸载了组件。然后,当组件卸载时,将其设置为
true

const mounted = useRef(true);

// this will set mounted to false when unmounting...
useEffect(() => () => { mounted.current = false; }, []);

useEffect(() => {
   axios.get(/**/).then(data => {
     if (mounted.current) {
       // do the state updates
     }
   })
}, [/* some requirements*/]);
或者完全没有参考号:

useEffect(() => {

   let mounted = true;

   axios.get(/**/).then(data => {
     if (mounted) {
       // do the state updates
     }
   })

   return () => mounted = false;
}, [/* some requirements*/]);

不同之处在于,在这种情况下,如果效果的任何依赖项发生更改,状态更新也将被取消。这甚至可以说是更好的解决方案。但这不是问题,因为另一个请求也将进入队列。

您可以使用一个ref,指示在执行所有状态更新之前是否卸载了组件。然后,当组件卸载时,将其设置为
true

const mounted = useRef(true);

// this will set mounted to false when unmounting...
useEffect(() => () => { mounted.current = false; }, []);

useEffect(() => {
   axios.get(/**/).then(data => {
     if (mounted.current) {
       // do the state updates
     }
   })
}, [/* some requirements*/]);
或者完全没有参考号:

useEffect(() => {

   let mounted = true;

   axios.get(/**/).then(data => {
     if (mounted) {
       // do the state updates
     }
   })

   return () => mounted = false;
}, [/* some requirements*/]);

不同之处在于,在这种情况下,如果效果的任何依赖项发生更改,状态更新也将被取消。这甚至可以说是更好的解决方案。但这不是问题,因为另一个请求也将排队。

如果您不想在卸载组件后呈现任何内容,则可以使用此代码示例来实现这一点

我已经创建了_IsMounted变量并将其设置为false。当调用useEffect时,这意味着安装了组件,所以它设置为true

当组件从屏幕上卸载时,react从useEffect调用返回方法,并将其设置为false。所以,当您尝试在没有安装组件的情况下更新状态时,不会导致崩溃

这不会取消订阅或异步代码,但不会影响应用程序或导致任何错误

let IS_MOUNTED = false; // define in global scope

useEffect(() => {

  IS_MOUNTED = true;
   
  thisIsFuntion();

  return (() => {
    IS_MOUNTED = false;
  })

},[])


const thisIsFuntion = () => {
   
   if(IS_MOUNTED)
   {
      // Update your state only if compoment is mounted
   }

}


如果您不想在卸载组件后渲染任何内容,那么可以使用此代码示例来实现这一点

我已经创建了_IsMounted变量并将其设置为false。当调用useEffect时,这意味着安装了组件,所以它设置为true

当组件从屏幕上卸载时,react从useEffect调用返回方法,并将其设置为false。所以,当您尝试在没有安装组件的情况下更新状态时,不会导致崩溃

这不会取消订阅或异步代码,但不会影响应用程序或导致任何错误

let IS_MOUNTED = false; // define in global scope

useEffect(() => {

  IS_MOUNTED = true;
   
  thisIsFuntion();

  return (() => {
    IS_MOUNTED = false;
  })

},[])


const thisIsFuntion = () => {
   
   if(IS_MOUNTED)
   {
      // Update your state only if compoment is mounted
   }

}


如果其他人遇到此问题,以下是解决方案代码

import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';

const isMounted = useRef(true);
useEffect(() => () => { isMounted.current = false; }, []);
useEffect(() => {
  if (reloadTable) {
    setReloadTable(false); // Forces this useEffect to be called once
  } else {
    let dataSelected = [];
    const options = {
      keyName: process.env.REACT_APP_KEY_NAME,
      keyValue: process.env.REACT_APP_KEY_VALUE
    }
    if(tab === "instructors"){
      setIsLoadingInstructorsTable(true);
      isMounted.current = true;
      axios.post(`https://example.com/school/api/Instructors/GetAllInstructors`, options)
      .then(data => {
          if(isMounted.current){
            dataSelected = data.data.instructors.map(instructorData => {
                return {id: instructorData.id, name: instructorData.name, assistants: instructorData.assistants, students: instructorData.students, hours: instructorData.hours, classes: instructorData.classes};
            });
            setTableInstructorData(dataSelected);
            setInstructorDisplayTableData(dataSelected);
            setListOfBooks(data.data.books);
            setListOfClasses(data.data.classes);
            setListOfcurriculums(data.data.datacurriculums);
            setListOfMeetings(data.data.);
            setIsLoadingInstructorsTable(false);
            setSearchTerm("");
            isMounted.current = false;
          }
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingInstructorsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      );
    }
    if(tab === "assistants"){
      setIsLoadingAssistantsTable(true);
      isMounted.current = true;
      axios.post(`https://example.com/school/api/Assistants/GetAllAssistants`, options)
      .then(data => {
          if(isMounted.current){
            dataSelected = data.data.assistants.map(assistantData => {
              return {id: assistantData.id, name: assistantData.name, hours: assistantData.hours};
            });
            setTableAssistantsData(dataSelected);
            setAssistantsDisplayTableData(dataSelected);
            setListOfBooks(data.data.books);
            setListOfClasses(data.data.classes);
            setListOfcurriculums(data.data.datacurriculums);
            setListOfMeetings(data.data.);
            setIsLoadingAssistantsTable(false);
            setSearchTerm("");
            isMounted.current = false;
          }
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingAssistantsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      );
    }
    if(tab === "students"){
      setIsLoadingStudentsTable(true);
      isMounted.current = true;
      axios.post(`https://example.com/school/api/Students/GetAllStudents`, options)
      .then(data => {
          if(isMounted.current){
            dataSelected = data.data.students.map(studentData => {
              return {id: assistantData.id, name: assistantData.name, books: assistantData.books, classes: assistantData.classes};
            });
            setTableStudentsData(dataSelected);
            setStudentsDisplayTableData(dataSelected);
            setListOfBooks(data.data.books);
            setListOfClasses(data.data.classes);
            setListOfcurriculums(data.data.datacurriculums);
            setListOfMeetings(data.data.);
            setIsLoadingStudentsTable(false);
            setSearchTerm("");
            isMounted.current = false;
          }
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingStudentsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      );
    }
  }
}, [tab, reloadTable]);

如果其他人遇到此问题,以下是解决方案代码

import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';

const isMounted = useRef(true);
useEffect(() => () => { isMounted.current = false; }, []);
useEffect(() => {
  if (reloadTable) {
    setReloadTable(false); // Forces this useEffect to be called once
  } else {
    let dataSelected = [];
    const options = {
      keyName: process.env.REACT_APP_KEY_NAME,
      keyValue: process.env.REACT_APP_KEY_VALUE
    }
    if(tab === "instructors"){
      setIsLoadingInstructorsTable(true);
      isMounted.current = true;
      axios.post(`https://example.com/school/api/Instructors/GetAllInstructors`, options)
      .then(data => {
          if(isMounted.current){
            dataSelected = data.data.instructors.map(instructorData => {
                return {id: instructorData.id, name: instructorData.name, assistants: instructorData.assistants, students: instructorData.students, hours: instructorData.hours, classes: instructorData.classes};
            });
            setTableInstructorData(dataSelected);
            setInstructorDisplayTableData(dataSelected);
            setListOfBooks(data.data.books);
            setListOfClasses(data.data.classes);
            setListOfcurriculums(data.data.datacurriculums);
            setListOfMeetings(data.data.);
            setIsLoadingInstructorsTable(false);
            setSearchTerm("");
            isMounted.current = false;
          }
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingInstructorsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      );
    }
    if(tab === "assistants"){
      setIsLoadingAssistantsTable(true);
      isMounted.current = true;
      axios.post(`https://example.com/school/api/Assistants/GetAllAssistants`, options)
      .then(data => {
          if(isMounted.current){
            dataSelected = data.data.assistants.map(assistantData => {
              return {id: assistantData.id, name: assistantData.name, hours: assistantData.hours};
            });
            setTableAssistantsData(dataSelected);
            setAssistantsDisplayTableData(dataSelected);
            setListOfBooks(data.data.books);
            setListOfClasses(data.data.classes);
            setListOfcurriculums(data.data.datacurriculums);
            setListOfMeetings(data.data.);
            setIsLoadingAssistantsTable(false);
            setSearchTerm("");
            isMounted.current = false;
          }
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingAssistantsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      );
    }
    if(tab === "students"){
      setIsLoadingStudentsTable(true);
      isMounted.current = true;
      axios.post(`https://example.com/school/api/Students/GetAllStudents`, options)
      .then(data => {
          if(isMounted.current){
            dataSelected = data.data.students.map(studentData => {
              return {id: assistantData.id, name: assistantData.name, books: assistantData.books, classes: assistantData.classes};
            });
            setTableStudentsData(dataSelected);
            setStudentsDisplayTableData(dataSelected);
            setListOfBooks(data.data.books);
            setListOfClasses(data.data.classes);
            setListOfcurriculums(data.data.datacurriculums);
            setListOfMeetings(data.data.);
            setIsLoadingStudentsTable(false);
            setSearchTerm("");
            isMounted.current = false;
          }
        }
      ).catch(err => {
          console.log('error:', err);
          setIsLoadingStudentsTable(false);
          setSearchTerm("");
          isMounted.current = false;
        }
      );
    }
  }
}, [tab, reloadTable]);

您可以使用useEffect的析构函数回调以及useState标志

const [isMounted, setIsMounted] = useState(false)

// Inside your useEffect
useEffect(() => {
    setIsMounted(true);

    //Inside your axios call
    axios.post(`https://example.com/school/api/Instructors/GetAllInstructors`, options)
        .then(data => {
            if (isMounted) {
              ...
              ...
     }
   });
   // destructor callback
   return () => {
     setIsMounted(false);
   }
});

您可以使用useEffect的析构函数回调以及useState标志

const [isMounted, setIsMounted] = useState(false)

// Inside your useEffect
useEffect(() => {
    setIsMounted(true);

    //Inside your axios call
    axios.post(`https://example.com/school/api/Instructors/GetAllInstructors`, options)
        .then(data => {
            if (isMounted) {
              ...
              ...
     }
   });
   // destructor callback
   return () => {
     setIsMounted(false);
   }
});

这确实有效,我唯一需要添加的是在axios之前,设置
mounted.current=true
,并在承诺返回后的if语句末尾设置
mounted.current=false
。如果我没有做这两件事,它会将加载设置为永久true,这样数据就不会填充。@FiddleFreak它应该已经通过传递初始值
useRef(true)
设置为
true
。您是否使用了两个独立的
useffect
s?您也可以完全不使用ref。我更新了我的答案。请也检查一下。这发生在制表符切换期间,因为一旦axios调用第二次发生,该值为false,因此if语句中的所有内容都不会执行。@FiddleFreak,但这实际上不可能,因为它仅在卸载时设置为
false
(不是在请求之后,因此两个独立的
useffect
s)如果组件再次挂载,它将创建一个新的ref,该ref将再次为
true
。但是没有ref的解决方案可能会更好。在选项卡之间切换时,组件不会卸载。只有在路由之间切换时,组件才会卸载。单击新选项卡会导致它加载该表的数据(讲师/助理/学生)。因此,一旦为一个选项卡/表加载数据,就无法为另一个选项卡/表加载数据,除非在进行axios调用之前将isMounted设置为true。请参阅我的参考解决方案代码答案。这肯定有效,我唯一需要添加的是在axios之前,设置
mounted.current=true
,并在if语句末尾在承诺返回集
mounted.current=false
之后。如果我没有做这两件事,它会将加载永久设置为true,这样数据就不会填充。@FiddleFreak它应该已经通过传递初始值
useRef(true)设置为
true
。您是否使用了两个独立的
useffect
s?您也可以不使用完全的ref来完成。我用它更新了我的答案。请也检查一下。这发生在制表符切换过程中,因为一旦axios调用第二次发生,该值为false,因此if语句中的所有内容都将永远不会执行。@FiddleFreak但这会发生ALY不应该是可能的,因为它仅在卸载时设置为
false
(不是在请求之后,因此两个单独的
useffect
s)如果组件再次挂载,它将创建一个新的ref,该ref将再次为
true
。但是没有ref的解决方案可能会更好。在选项卡之间切换时,组件不会卸载。只有在路由之间切换时,组件才会卸载。单击新选项卡会导致它加载该表的数据(讲师/助理/学生)所以