反应:未捕获的不变违规:无效的挂接调用

时间:2019-09-01 03:46:19

标签: reactjs

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

导致错误的行是:

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;

1 个答案:

答案 0 :(得分:1)

就像错误一样,根据rules of Hooks,您在getStyle中的挂接调用无效。让我们快速检查一下规则:

仅位于React函数顶层的呼叫挂钩✅。

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

从React函数组件或自定义挂钩中调用挂钩❌。

什么是React函数组件?基本上,所有功能都是通过JSX语法(例如<MyComp />或其等效的React.createElement(MyComp, null))使用的。在您的情况下,getStyle是一个普通函数,在LoginForm组件中的某处被调用,并且包含一个Hook-因此是不允许的。您已经在useUserContext中使用了LoginForm,所以只需将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;