如何在React Native应用程序中使用React钩子useEffect每隔5秒渲染一次setInterval?

时间:2019-08-18 06:41:04

标签: javascript react-native setinterval react-hooks use-effect

我有React Native个应用,并且APIfetch获取了数据。我创建了自定义挂钩,用于从API获取数据。而且我需要每5秒重新渲染一次。为此,我将自定义钩子包装到setInterval,并且应用程序运行缓慢之后,当我导航到另一个屏幕时,出现此错误:

  

无法在已卸载的组件上执行React状态更新。这是   无操作,但表示您的应用程序内存泄漏。修理,   取消useEffect清理中的所有订阅和异步任务   功能。

请告诉我如何解决此错误,这将是解决setInterval的最佳方法,因为我认为我的方法不好。

我的自定义挂钩:

export const useFetch = url => {
  const [state, setState] = useState({ data: null, error: false, loading: true })

  useEffect(() => {
    setInterval(() => {
      setState(state => ({ data: state.data, error: false, loading: true }))
      fetch(url)
        .then(data => data.json())
        .then(obj =>
          Object.keys(obj).map(key => {
            let newData = obj[key]
            newData.key = key
            return newData
          })
        )
        .then(newData => setState({ data: newData, error: false, loading: false }))
        .catch(function(error) {
          console.log(error)
          setState({ data: null, error: true, loading: false })
        })
    }, 5000)
  }, [url, useState])
  useEffect(() => () => console.log('unmount'), [])
  return state
}

我的组件

const ChartsScreen = ({ navigation }) => {
  const { container } = styles
  const url = 'https://poloniex.com/public?command=returnTicker'
  const { data, error, loading } = useFetch(url)

  const percentColorHandler = number => {
    return number >= 0 ? true : false
  }

  return (
    <View style={container}>
      <ProjectStatusBar />
      <IconsHeader
        dataError={false}
        header="Charts"
        leftIconName="ios-arrow-back"
        leftIconPress={() => navigation.navigate('Welcome')}
      />
      <ChartsHeader />
      <ActivityIndicator animating={loading} color="#068485" style={{ top: HP('30%') }} size="small" />
      <FlatList
        data={data}
        keyExtractor={item => item.key}
        renderItem={({ item }) => (
          <CryptoItem
            name={item.key}
            highBid={item.highestBid}
            lastBid={item.last}
            percent={item.percentChange}
            percentColor={percentColorHandler(item.percentChange)}
          />
        )}
      />
    </View>
  )
}

3 个答案:

答案 0 :(得分:2)

您需要清除interval

useEffect(() => {
  const intervalId = setInterval(() => {  //assign interval to a variaable to clear it
    setState(state => ({ data: state.data, error: false, loading: true }))
    fetch(url)
      .then(data => data.json())
      .then(obj =>
        Object.keys(obj).map(key => {
          let newData = obj[key]
          newData.key = key
          return newData
        })
     )
     .then(newData => setState({ data: newData, error: false, loading: false }))
     .catch(function(error) {
        console.log(error)
        setState({ data: null, error: true, loading: false })
     })
  }, 5000)

  return () => clearInterval(intervalId); //This is important

}, [url, useState])

有关cleanup中的useEffect函数的更多信息,请参考this

答案 1 :(得分:2)

可能是这两个东西

  • 您需要清理间隔
  • 如果未卸载API回调,则无需更新状态。

代码:

useEffect(() => {
   let isMounted = true
   const intervalId = setInterval(() => {  //assign interval to a variaable to clear it
    setState(state => ({ data: state.data, error: false, loading: true }))
    fetch(url)
      .then(data => data.json())
      .then(obj =>
        Object.keys(obj).map(key => {
          let newData = obj[key]
          newData.key = key
          return newData
        })
     )
     .then(newData => {
        if(!isMounted) return  // This will cancel the setState when unmounted
        setState({ data: newData, error: false, loading: false })
     })
     .catch(function(error) {
        console.log(error)
        setState({ data: null, error: true, loading: false })
     })
   }, 5000)

   return () => {
       clearInterval(intervalId); //This is important
       isMounted = false // Let's us know the component is no longer mounted.
   }

}, [url, useState])

可能需要根据服务器响应时间,为挂起的查询添加故障保护(例如,如果您发出查询,并且下一个查询在第一个查询返回之前启动...)。

答案 2 :(得分:0)

React Hooks + Apollo 每 5 秒从 GraphQL 服务器获取数据。 在这个例子中,如果用户没有在后端登录,我们在 React 中注销用户。 (JWT 令牌不再有效)

Private Sub Workbook_Open()

Dim WB As Workbook
On Error Resume Next
    Set WB = Workbooks("Test.xlsx")
    If Err Then
        MsgBox "Test" & vbNewLine & "" & vbNewLine & "" & "Test" & vbNewLine & "" & vbNewLine & "Test" & vbNewLine & "" & vbNewLine & "Test"
    'ThisWorkbook.Close
    End If

Workbooks("TestA.xlsx").Worksheets("TestA").ShowAllData
Workbooks("TestA.xlsx").Worksheets("TestA").Range("A2:AF666").Copy _
Workbooks("TestB.xlsm").Worksheets("TestB").Range("A2")
Worksheets("TestC").Range("A1").AutoFilter Field:=1, Criteria1:="JA"
Workbooks("TestB.xlsm").Worksheets("TestB").Range("B2:AF666").Copy _
Workbooks("TestB.xlsm").Worksheets("TestC").Range("B2")

On Error GoTo 0

End Sub