React Hooks问题:无法处理的拒绝(TypeError):无法读取未定义的属性“ signup”

时间:2019-11-13 19:52:33

标签: javascript reactjs react-hooks

我正在尝试实现https://usehooks.com/中的useAuth钩子

useAuth.js

// Hook (use-auth.js)

import React, { useState, useEffect, useContext, createContext } from "react";
import axios from 'axios';

//Credentials


const authContext = createContext();

// Provider component that wraps your app and makes auth object ...
// ... available to any child component that calls useAuth().
export function ProvideAuth({ children }) {
  const auth = useProvideAuth();
  return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}

// Hook for child components to get the auth object ...
// ... and re-render when it changes.
export const useAuth = () => {
  return useContext(authContext);
};

// Provider hook that creates auth object and handles state
function useProvideAuth() {

  const [user, setUser] = useState(null);
  const API_URL = "http://localhost:1038";

  // Wrap any Firebase methods we want to use making sure ...
  // ... to save the user to state.
  const signin = (email, password) => {
    return firebase
      .auth()
      .signInWithEmailAndPassword(email, password)
      .then(response => {
        setUser(response.user);
        return response.user;
      });
  };

  const register = (username, email, password) => {
    return firebase
      .auth()
      .createUserWithEmailAndPassword(email, password)
      .then(response => {
        setUser(response.user);
        return response.user;
      });
  };

  const signup = async (data) => {
    const SIGNUP_ENDPOINT = `${API_URL}/wp-json/wp/v2/users/register`;
    let response = '';
    try {
        response = await axios({
            method: 'post',
            responseType: 'json',
            url: SIGNUP_ENDPOINT,
            data: data
          });
    } catch(e){
        console.log(e);
    }
    console.log(response);
  };

  const signout = () => {
    return firebase
      .auth()
      .signOut()
      .then(() => {
        setUser(false);
      });
  };

  const sendPasswordResetEmail = email => {
    return firebase
      .auth()
      .sendPasswordResetEmail(email)
      .then(() => {
        return true;
      });
  };

  const confirmPasswordReset = (code, password) => {
    return firebase
      .auth()
      .confirmPasswordReset(code, password)
      .then(() => {
        return true;
      });
  };

  // Return the user object and auth methods
  return {
    user,
    signin,
    signup,
    register,
    signout,
    sendPasswordResetEmail,
    confirmPasswordReset
  };
}

form register.js

import Link from 'next/link';
import Layout from '../components/layout';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faEnvelope, faCheck, faLock, faUser } from '@fortawesome/free-solid-svg-icons'

import useForm from 'react-hook-form'
import { useAuth } from "../hooks/useAuth";


export default function Register(props) {

    // Get auth state and re-render anytime it changes
    const auth = useAuth();
    const { register, handleSubmit, watch, errors } = useForm();
    const onSubmit = data => { auth.signup(data) }

    return (
        <Layout>
            <div className="container mt-sm p-md">
                <div className="columns">
                    <div className="column">

                    </div>
                    <div className="column">
                        <form onSubmit={handleSubmit(onSubmit)}>
                        <div className="field">
                        <label className="label">Username</label>
                        <div className="control has-icons-left has-icons-right">
                            <input className="input is-success" type="text" placeholder="Username" name="username" ref={register({ required: true })}/>
                            <span className="icon is-small is-left">
                            <FontAwesomeIcon icon={faUser}/>
                            </span>
                            <span className="icon is-small is-right">
                            <FontAwesomeIcon icon={faCheck}/>
                            </span>
                        </div>
                        {errors.username && <p className="help is-danger">This username is invalid</p>}
                        </div>

                        <div className="field">
                        <label className="label">Email</label>
                        <div className="control has-icons-left has-icons-right">
                            <input className="input is-success" type="text" placeholder="Email" name="email" ref={register({ required: true , pattern: /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/})}/>
                            <span className="icon is-small is-left">
                            <FontAwesomeIcon icon={faEnvelope}/>
                            </span>
                            <span className="icon is-small is-right">
                            <i className="fas fa-exclamation-triangle"></i>
                            </span>
                        </div>
                        {errors.email && <p className="help is-danger">This email is invalid</p>}
                        </div>
                        <div className="field">
                        <label className="label">Password</label>
                            <div className="control has-icons-left">
                                <input className="input" type="password" placeholder="Password" name="password" ref={register({ required: true , pattern: /^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})/ })}/>
                                <span className="icon is-small is-left">
                                <FontAwesomeIcon icon={faLock}/>
                                </span>
                            </div>
                        </div>
                        {errors.password && <p className="help is-danger">This password is too weak</p>}
                        <div className="field">
                        <label className="label">Confirm Password</label>
                            <div className="control has-icons-left">
                                <input className="input" type="password" placeholder="Confirm Password" name="confirm_password" ref={register({ required: true , validate: (value) => { return value === watch('password')} })}/>
                                <span className="icon is-small is-left">
                                <FontAwesomeIcon icon={faLock}/>
                                </span>
                            </div>
                        </div>
                        {errors.confirm_password && <p className="help is-danger">This password do not match</p>}
                        <div className="field">
                        <div className="control">
                            <label className="checkbox">
                            <input type="checkbox" name="terms" ref={register({ required: true })}/>
                            I agree to the <Link href='/'><a>terms and conditions</a></Link>
                            </label>
                        </div>
                        </div>
                        {errors.terms && <p className="help is-danger">You must agree to the terms and conditions</p>}

                        <div className="field is-grouped">
                        <div className="control">
                            <button className="button is-link">Submit</button>
                        </div>
                        <div className="control">
                            <button className="button is-link is-light" type="submit">Cancel</button>
                        </div>
                        </div>
                    </form> 
                    </div>
                    <div className="column">

                    </div>
                </div>

            </div>
        </Layout>
    )
}

提交表单时出现错误,我调用useAuth挂钩。

Unhandled Rejection (TypeError): Cannot read property 'signup' of undefined
onSubmit
./pages/register.js:15
  12 | // Get auth state and re-render anytime it changes
  13 | const auth = useAuth();
  14 | const { register, handleSubmit, watch, errors } = useForm();
> 15 | const onSubmit = data => { auth.signup(data) }
     | ^  16 | 
  17 | return (
  18 |  <Layout>

关于我哪里出错了的任何想法。该钩子本来可以与firebase一起使用,但是我会在wordpress上对其进行修改,因此现在仅设置了注册功能。

Layout.js

    import Head from 'next/head'
    import Link from 'next/link'
    import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
    import { faCoffee } from '@fortawesome/free-solid-svg-icons'
    import '../styles/styles.sass'
    import { ProvideAuth } from "../hooks/useAuth";

    export default ({ children }) => {

    const toggleStyles = (event) => {
    document.querySelector('#burger').classList.toggle('is-active')
    document.querySelector('#navbarmenu').classList.toggle('is-active')
     }

    return (
    <ProvideAuth>
    <div>
      <Head>
        <title>Quiz Client</title>
        <meta name="viewport" content="initial-scale=1.0, width=device- 
     width"/>
      </Head>
      <header>
        <nav className="navbar is-primary" role="navigation" aria- 
         label="main navigation">
          <div className="navbar-brand">
            <a className="navbar-item">
                    <FontAwesomeIcon icon={faCoffee} />
            </a>
            <a id="burger" onClick={toggleStyles} 
                role="button" className="navbar-burger burger" aria- 
       label="menu" aria-expanded="false" data-target="navbarmenu">
              <span aria-hidden="true"></span>
              <span aria-hidden="true"></span>
              <span aria-hidden="true"></span>
            </a>
          </div>
          <div id="navbarmenu" className="navbar-menu">
            <div className="navbar-start">
              <Link prefetch href="/">
                <a className="navbar-item">Home</a>
              </Link>
              <Link prefetch href="/elsewhere">
                <a className="navbar-item">Elsewhere</a>
              </Link>
            </div>

            <div className="navbar-end"> 
              <Link prefetch href="/login">
                <a className="navbar-item">Login</a>
              </Link>
              <Link prefetch href="/register">
                <a className="navbar-item">Register</a>
              </Link>           
            </div>
          </div>
        </nav>
      </header>
      {children}
      <footer className="footer">
        <div className="content has-text-centered">
          <span>I'm the footer</span>
        </div>
      </footer>
      </div>
      </ProvideAuth>
      )
      }

请原谅

1 个答案:

答案 0 :(得分:1)

您的Register提供者未包装您的ProvideAuth组件。您可以通过稍微重新排列组件来解决此问题

function RegisterForm(props) {

  // Get auth state and re-render anytime it changes
  const auth = useAuth();
  const { register, handleSubmit, watch, errors } = useForm();
  const onSubmit = data => { auth.signup(data) }

  return (
    <div className="container mt-sm p-md">
      {/* the rest of your form */}
    </div>
  )
}

export default function Register(props) {
  return (
    <Layout>
      <RegisterForm />
    </Layout>
  )
}