有条件地调用React Hook的“ useEffect”

时间:2019-08-23 06:19:38

标签: javascript reactjs react-hooks

React抱怨下面的代码,说它的useEffect被有条件地调用:

import React, { useEffect, useState } from 'react'
import VerifiedUserOutlined from '@material-ui/icons/VerifiedUserOutlined'
import withStyles from '@material-ui/core/styles/withStyles'
import firebase from '../firebase'
import { withRouter } from 'react-router-dom'

function Dashboard(props) {
  const { classes } = props
  
  const [quote, setQuote] = useState('')

	if(!firebase.getCurrentUsername()) {
		// not logged in
		alert('Please login first')
		props.history.replace('/login')
		return null
	}

	useEffect(() => {
		firebase.getCurrentUserQuote().then(setQuote)
	})

	return (
		<main>
			// some code here
		</main>
	)

	async function logout() {
		await firebase.logout()
		props.history.push('/')
	}
}

export default withRouter(withStyles(styles)(Dashboard))

然后返回错误:

  Line 48:  React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render  react-hooks/rules-of-hooks

有人碰巧知道这里是什么问题吗?

4 个答案:

答案 0 :(得分:7)

在包含- (void)createCVBufferWithSize:(CGSize)size withRenderTarget:(CVPixelBufferRef *)target withTextureOut:(CVOpenGLESTextureRef *)texture { CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, _context, NULL, &_textureCache); if (err) return; CFDictionaryRef empty; CFMutableDictionaryRef attrs; empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty); CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32BGRA, attrs, target); CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCache, *target, NULL, // texture attributes GL_TEXTURE_2D, GL_RGBA, // opengl format size.width, size.height, GL_BGRA, // native iOS format GL_UNSIGNED_BYTE, 0, texture); CFRelease(empty); CFRelease(attrs); } 的{​​{1}}语句之后,您的代码等效于:

if

这意味着它是有条件执行的(仅当未执行return时)。

要解决:

if(!firebase.getCurrentUsername()) {
    ...
    return null
} else {
    useEffect(...)
    ...
}

答案 1 :(得分:1)

请勿在循环,条件或嵌套函数中调用Hook。相反,请始终在您的React函数的顶层使用挂钩。 您可以遵循文档here

在上面的代码中找不到用例。如果您需要在firebase.getCurrentUsername()的返回值更改时运行效果,则可能希望在if条件之外使用它,例如:

useEffect(() => {
    firebase.getCurrentUserQuote().then(setQuote)
}, [firebase.getCurrentUsername()]);

答案 2 :(得分:1)

我认为有一种方法可以有条件地调用钩子。您只需要从该挂钩中导出一些成员即可。将此代码段复制并粘贴到codeandbox中:

import React from "react";
import ReactDOM from "react-dom";

function useFetch() {
  return {
    todos: () =>
      fetch("https://jsonplaceholder.typicode.com/todos/1").then(response =>
        response.json()
      )
  };
}

const App = () => {
  const fetch = useFetch(); // get a reference to the hook

  if ("called conditionally") {
    fetch.todos().then(({title}) => 
      console.log("it works: ", title)); // it works:  delectus aut autem  
  }

  return null;
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

答案 3 :(得分:0)

这里的问题是,当我们从null返回if block时,useEffect钩子代码将无法访问,因为我们之前返回了钩子代码,因此错误是被有条件地调用。

您可能想先定义所有的钩子,然后开始编写用于渲染的逻辑,无论是null还是空字符串,还是有效的JSX。