【问题标题】:React: Uncaught Invariant Violation: Invalid hook call反应:未捕获的不变违规:无效的钩子调用
【发布时间】:2019-09-02 00:28:40
【问题描述】:

不确定为什么这一行会导致问题。看来我正确使用了钩子。

导致错误的行是:

const { theme } = useUserContext();

getStyle 函数中。如果我删除此行,则组件加载正常。有什么想法吗?

在我看来,我正在遵循挂钩规则。

import React, {useEffect, useRef, useState} from 'react';
import { Text, Button, TextInput, View, StyleSheet, Linking } from 'react-native';
import { Formik, FormikProps, ErrorMessage } from 'formik';
import * as Yup from 'yup';
import { WideButton } from '../../../components/Buttons';
import { HeaderText, ErrorText, LinkText } from '../../../components/StyledText';
import Colors from '../../../constants/Colors';
import { useUserContext } from "../../../context/UserContext";
import { RenderErrorMessage } from "../com/FormMessage";

const LoginForm = (props) => {

  const { user, logon, logoff } = useUserContext();
  const [loginErrorMessage, setLoginErrorMessage] = useState("");
  const usernameRef = useRef();

  const onLoginSubmit = (values, actions) => {
    axios.post(config.aogApiUrl + '/users/authenticate', values)
    .then(res => {
      //console.log(res.data);
      setLoginErrorMessage("");
      logon(res.data);
      setShowLoginModal(false);
      props.navigation.goBack();
    })
    .catch(error =>{
      let errorMsg = error.response ? error.response.data : error.message;
      setLoginErrorMessage(errorMsg);
      actions.setSubmitting(false);
    });
  }

  useEffect(() => {
    usernameRef.current.focus();
  });

  return (

    <Formik
      initialValues={{ username: 'jason', password: 'Yankees1'}}
      validationSchema={LoginSchema}
      onSubmit={(values, actions) => {
        props.onSubmit(values, actions);
      }}
    >
       {({ handleChange, handleBlur, handleSubmit, values, errors, touched, isSubmitting }) => (

        <View style={getStyle('container')} >

          <HeaderText>Log in to AOG</HeaderText>

          <RenderErrorMessage errorMessage={loginErrorMessage} />

          <TextInput
            name="username"
            autoComplete="username"
            ref={usernameRef}
            style={getStyle('textInput')}
            placeholder="Username"
            onChangeText={handleChange('username')}
            //onBlur={handleBlur('username')}
            value={values.username} />
          <ErrorMessage name="username">{msg => <ErrorText>{msg}</ErrorText>}</ErrorMessage> 

          <View style={{marginVertical: 5}} />

          <TextInput 
            name="password"
            autoComplete="current-password"
            style={getStyle('textInput')}
            placeholder="Password"
            onChangeText={handleChange('password')}
            //onBlur={handleBlur('password')}
            value={values.password}
            secureTextEntry={true}
            onSubmitEditing={handleSubmit} />
          <ErrorMessage name="password">{ msg => <ErrorText>{msg}</ErrorText> }</ErrorMessage>

          <View style={{marginVertical: 5}} />

          <View style={getStyle('submitContainer')}>
            <WideButton 
                onPress={handleSubmit}
                title="Submit"
                label="Click to submit" />
          </View>

          <View style={getStyle('linkContainer')}>
            <LinkText>Forgot password?</LinkText>
            <LinkText>Forgot username?</LinkText>
            <LinkText>Need to Register?</LinkText>
          </View>


        </View>
      )}
    </Formik>
  );

}

const LoginSchema = Yup.object().shape({
  username: Yup.string()
    .min(3, 'Too Short!')
    .max(15, 'Too Long!')
    .required('Username is required!'),
  password: Yup.string()
    .min(6, 'Must be at least 6 characters')
    .required('Password is required!'),
});

const getStyle = (style) => {

  const { theme } = useUserContext();

  const styles = {
    container:{
      margin: 20,
    },
    submitContainer: {
      marginTop: 12,
      marginBottom: 12
    },
    linkContainer:{
      flex:1,
      flexDirection: 'row',
      alignItems: 'flex-start',
      marginTop: 12,
      justifyContent: 'space-between'
    },
    textInput:{
      height: 40,
      width: 'auto',
      borderColor: 'gray',
      backgroundColor: '#E3B39C',
      borderWidth: 1,
      padding: 15,
      borderRadius: 20,
      fontSize: 18,
      margin: 5
    }
  }
  return StyleSheet.flatten(styles[style]);
};

export default LoginForm;

【问题讨论】:

标签: reactjs


【解决方案1】:

正如错误所说,根据rules of Hooks,您在getStyle 中的挂钩调用无效。让我们快速检查一下规则:

仅在 React 函数的顶层调用 Hooks ✅.

getStyle 在其函数体顶部调用useUserContext()

从 React 函数组件或自定义 Hooks 调用 Hooks ❌。

什么是 React 函数组件?基本上所有的函数,你都可以通过 JSX 语法来使用,比如 &lt;MyComp /&gt; 或者它的 transpiled 等价的 React.createElement(MyComp, null)。在您的情况下,getStyle 是一个普通函数,它在 LoginForm 组件中的某处被调用并包含一个 Hook - 因此这是不允许的。您已经在LoginForm 中使用了useUserContext,所以只需将theme 作为参数传递给getStyle

const LoginForm = props => {
  // 1. add theme here
  const { user, logon, logof, theme } = useUserContext(); 

  return (
    <Formik ...>
      {({ ... }) => (
        // 2. everywhere you use getStyle, also pass in the theme as argument
        <View style={getStyle("container", theme)}>
          <HeaderText>Log in to AOG</HeaderText>
         ...
        </View>
      )}
    </Formik>
  );
};

// 3. Add second argument theme
const getStyle = (style, theme) => {
  // do what you want with theme here
  return ...
};

export default LoginForm;

【讨论】:

    猜你喜欢
    • 2020-12-01
    • 2016-07-20
    • 2022-06-10
    • 1970-01-01
    • 2020-12-02
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    • 1970-01-01
    相关资源
    最近更新 更多