【问题标题】:Firebase: adding authentication to a react appFirebase:向反应应用程序添加身份验证
【发布时间】:2020-04-01 13:49:14
【问题描述】:

我试图理解this tutorial

注册表单中的handleSubmit方法有这个方法:

onSubmit = (event) => {
  const { username, email, passwordOne } = this.state;
  this.props.firebase
    .doCreateUserWithEmailAndPassword(email, passwordOne)
    .then(authUser => {
      this.setState({ ...INITIAL_STATE });
      this.props.history.push(ROUTES.HOME);
    })
    .catch(error => {
      this.setState({ error });
    });
  event.preventDefault();
}

它不起作用。它会生成一条错误消息:

{代码:“auth/argument-error”,消息:“createUserWithEmailAndPassword 失败:第一个参数“email”必须是有效字符串。“}

我发现 this post 这表明本教程可能落后于当前版本的 firebase(尽管这没有意义,因为该帖子的日期早于本教程,并且本教程在我尝试使用实时数据库时有效- 我现在正在尝试将它与 Cloud Firestore 一起使用)。这篇文章表明问题在于该方法如何要求表单中的值。

我已经尝试了 5 种不同的方式来询问该信息 - console.logs 都以未定义的形式返回。我没有猜测要找到表单值以知道如何替换 onSubmit 方法中给出的名称。

目前,该表单具有以下内容 - 对 onSubmit 方法的当前尝试的注释替代方法是在其他教程中引用的尝试 - 它们也不起作用,如果其他人尝试过,它们只是作为想法在帖子中类似的东西。

import React from 'react';
import { withRouter } from 'react-router';
import Firebase, { withFirebase } from '../../firebase';
import { compose } from 'recompose';
import * as ROUTES from '../../../constants/routes';
import { Button, Modal, Form, Input, Icon, Radio } from 'antd';

const DASHBOARD = '/dash';

const initialValues = {
  name: "",
  password: "",
  email: "",
  role: "",
  createdAt: ''
  }

const CollectionCreateForm = Form.create({ name: 'form_in_modal' })(
  // eslint-disable-next-line
  class extends React.Component {
    render() {

      const { visible, onCancel, onCreate, form } = this.props;
      const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched } = form;
      const passwordError = isFieldTouched('password') && getFieldError('password');

      return (
        <Modal
          visible={visible}
          title="Register"
          okText="Submit"
          onCancel={onCancel}
          onOk={onCreate}
        >
          <Form layout="vertical">

            <Form.Item label="Name">
              {getFieldDecorator('name', {
                rules: [{ required: true, message: 'Your full name' }],
              })(<Input />)}
            </Form.Item>
            <Form.Item label="Password" validateStatus={passwordError ? 'error' : ''} help={passwordError || ''}>
                {getFieldDecorator('password', {
                    rules: [{ required: true, message: 'Create a password' }],
                })(
                    <Input

                    type="password"
                    placeholder="Minimum 6 characters"
                    />,
                )}
            </Form.Item>


            <Form.Item label="Email">
              {getFieldDecorator('email', {
                rules: [{ required: true, message: 'Your email address' }],
              })(<Input />)}
            </Form.Item>

            <Form.Item label="Select your role">
              {getFieldDecorator('role', {
                initialValue: 'test',
              })(
                <Radio.Group>
                  <Radio value="test1">1</Radio>
                  <Radio value="test2">2 R&D</Radio>

                </Radio.Group>,
              )}
            </Form.Item>

          </Form>
        </Modal>
      );
    }
  },
);

class RegisterBase extends React.Component {
  state = {
    visible: false,
  };

  showModal = () => {
    this.setState({ visible: true });
  };

  handleCancel = () => {
    this.setState({ visible: false });
  };

  // handleCreate = values => {
  //   // values.preventDefault();

  //   const { name, email, password } = this.state;

//     Firebase
//     .doCreateUserWithEmailAndPassword = (email, password) => {
//       return this.auth
//         .createUserWithEmailAndPassword(email, password)
//         .then((res) => {
//         
// Firebase.firestore().collection("users").doc(res.user.uid).set({

//           email: values.email,
//           name: values.name,
//           role: values.role,
//           createdAt: Firebase.FieldValue.serverTimestamp()
//         }).then(() => this.history.push(ROUTES.DASHBOARD));
//       })
//       .catch(err => {
//         console.log(err.message);
//       });
//   };
// };
  // handleCreate = () => {
  //   const { form } = this.formRef.props;
  //   form.validateFields((err, values) => {
  //     if (err) {
  //       return;
  //     };
  //   const payload = {
  //   // ...values,
  //   name: values.name,
  //   email: values.email,
  //   organisation: values.organisation,
  //   beta: values.beta,
  //   role: values.role,
  //   // createdAt: Firebase.FieldValue.serverTimestamp()
  //   }
  //   console.log("formvalues", payload);

  //   Firebase
  //   .auth()
  //   
// .createUserWithEmailAndPassword(values.email, values.password)
  //   console.log('Received values of form: ', values);
  //   Firebase
  //   .collection("users")
  //   .add(payload)
  //   // .then(docRef => {
  //   //     resetForm(initialValues);
  //   // })
  //   .then(e => this.setState({ modalShow: true }))


  //   form.resetFields();
  //   this.setState({ visible: false });
  //   this.props.history.push(DASHBOARD);

  // });

    // };
  handleCreate = (event) => {
   // const {  email, password } = this.state;
    const {  email, password } = this.formRef.props.state;



// console.log(this.state.email)

console.log(email);
    this.formRef.props.firebase

    .doCreateUserWithEmailAndPassword(email, password)
    .then(authUser => {
    this.setState({ ...initialValues });
    this.props.history.push(ROUTES.DASHBOARD);
    })
    .catch(error => {
      this.setState({ error });
      });
      event.preventDefault();
    };

  saveFormRef = formRef => {
    this.formRef = formRef;
  };

  render() {
    return (
      <React.Fragment>
          <Button type="primary" onClick={this.showModal} >
            GET STARTED
          </Button>

            <CollectionCreateForm
              wrappedComponentRef={this.saveFormRef}
              visible={this.state.visible}
              onCancel={this.handleCancel}
              onCreate={this.handleCreate}
            />


      </React.Fragment>
    );
  };
}
const Register = compose(
  withRouter,
  withFirebase,
)(RegisterBase);

export default Register;

一个奇怪的事情是 console.log(firebase) 和 console.log(Firebase) 都返回未定义的值。该表单应该使用 withFirebase HOC,其定义为:

import React from 'react';
const FirebaseContext = React.createContext(null);
export const withFirebase = Component => props => (
  <FirebaseContext.Consumer>
    {firebase => <Component {...props} firebase={firebase} />}
  </FirebaseContext.Consumer>
);
export default FirebaseContext;

关于尝试从该表单中获取电子邮件和密码值的任何想法?

下一次尝试 尝试 Doppio 的建议,我正在尝试:

const CollectionCreateForm = Form.create({ name: 'form_in_modal' })(
  // eslint-disable-next-line
  class extends React.Component {
    handleCreate = e => {
      e.preventDefault();
      this.props.form.validateFields((err, values) => {
        if (!err) {
          console.log('Received values of form: ', values);
        }
        // Get email, password from form values... 
        // key is the one you use in getFieldDecorator 
        const { email, password } = values;

        this.props.onCreate(values);
      });
    };

注意:此块中的 console.log 不会运行。

然后,在 RegisterBase 中,我有:

handleCreate = (values) => {
      const {  email, password } = values;
      console.log(values)


      this.props.firebase
      .doCreateUserWithEmailAndPassword(this.email, this.password)
      .then(authUser => {
      this.setState({ ...initialValues });
      this.props.history.push(ROUTES.DASHBOARD);
      })
      .catch(error => {
        this.setState({ error });
        });
        values.preventDefault();
      };

此控制台日志不会记录表单中的条目。相反,它会记录一些以以下开头的巨大列表:

类 {dispatchConfig: {…}, _targetInst: FiberNode, _dispatchListeners: Array(2), _dispatchInstances: Array(2), nativeEvent: MouseEvent, ...}

然后,错误消息说:

M {code: "auth/argument-error", message: “createUserWithEmailAndPassword 失败:第一个参数“email”必须是 一个有效的字符串。"}code: "auth/argument-error"message: “createUserWithEmailAndPassword 失败:第一个参数“email”必须是 一个有效的字符串。”proto:错误

下一次尝试

handleCreate = (event) => {
    //   const {  email } = this.props.form.getFieldsValue().email;
      // console.log(this.props.form.getFieldsValue().email)

      // const {  password } = this.props.form.getFieldsValue().password;

      // console.log(withFirebase);
      this.props.firebase
      // .console.log(this.email)
      .doCreateUserWithEmailAndPassword(this.props.form.getFieldsValue().email, this.props.form.getFieldsValue().password)
      .then(authUser => {
      this.setState({ ...initialValues });
      this.props.history.push(ROUTES.DASHBOARD);
      })
      .catch(error => {
        this.setState({ error });
        });
        event.preventDefault();
      };

这个公式也不起作用。错误消息说:

TypeError: Cannot read property 'getFieldsValue' of undefined

下一次尝试

采用 Doppio 的新建议,我可以通过控制台将输入的值记录到表单中。我尝试调整提交处理程序以将它们与以下内容一起使用:

handleCreate = () => {
      console.log(this.formRef);
      const { form } = this.formRef.props;
      form.validateFields((err, values) => {
        if (err) {
          console.log(err);
          return;
        }

        console.log("Received values of form: ", values);
        const { email, password } = values;
        console.log(Firebase)
        // console.log(firebase)
        this.props.firebase
          .auth()
          .createUserWithEmailAndPassword(values.email, values.password)
          .then(authUser => {
            console.log({ authUser });
          })
          .catch(error => {
            this.setState({ error });
          });
          form.resetFields();
            this.setState({ visible: false });
            this.props.history.push(DASHBOARD);
        // form.resetFields();
        // this.setState({ visible: false });
      });
    };

console.log(Firebase) 之外的任何东西都不起作用。表单只是挂起,并没有提交到 firebase。

我想知道第一个console.log 中是否有线索。它的输出是巨大的——第一部分开始了:

{props: {…}, context: {…}, refs: {…}, updater: {…}, _reactInternalFiber: FiberNode, …}
context: {}
props:
form:
getFieldDecorator: ƒ ()
getFieldError: ƒ (name)

我找不到包含表单值的菜单或其中的 firebase HOC。我没有在该日志中的每个下拉菜单中进行搜索,但我找不到任何可能包含该信息的暗示性标题。

当我尝试这样做时:

console.log(this.props.firebase)

它确实返回了一长串以这一行开头的难以辨认的东西:

Firebase {auth: Km, db: Firestore, doCreateUserWithEmailAndPassword: ƒ}

在该日志中,在标有“a”的菜单下 - 记录了我的 firebase 应用程序的详细信息。我是否应该在 this.props.firebase 之后连接对每个菜单标题的引用以使方法运行?

下一个洞察

handleCreate = () => {
      console.log(this.formRef);
      const { form } = this.formRef.props;
      form.validateFields((err, values) => {
        if (err) {
          console.log(err);
          return;
        }


    console.log("Received values of form: ", values);
    const { email, password } = values;
    // console.log(Firebase)
    // console.log(this.form.props.firebase)
    // console.log(this.formRef.props)
    console.log(this.props.firebase)
    this.props.firebase
      .auth()
      .createUserWithEmailAndPassword(values.email, values.password)
      .console.log("try to check if create worked", values.email)
      .then(authUser => {
        console.log("logging user", { authUser });
        this.setState({ ...initialValues });
        this.props.history.push(DASHBOARD);
      })
      .catch(error => {
        this.setState({ error });
      });
      form.resetFields();
        this.setState({ visible: false });
        this.props.history.push(DASHBOARD);
    // form.resetFields();
    // this.setState({ visible: false });
  });
  // form.preventDefault();
};

此方法中最后一个有效的 console.log 是:console.log(this.props.firebase)。其余的在控制台中无法识别。如果 this.props.firebase 被识别,是否有可能得到错误的东西 - 也许我应该在它返回的下拉菜单的长列表中寻找看起来像我的 firebase 配置中的 auth const 的东西.这听起来像是一个合乎逻辑的询问方式吗?

下一条线索

在此尝试中,我尝试记录 firebase.auth 而不是 firebase.auth() 的值。我的 firebase 配置将 this.auth 定义为 firebase.auth()。记录的值返回另一堆我无法解释的乱码,但开头是:

Km {l: false, settings: Al, app: FirebaseAppImpl, b: ni, O: Array(0), …}
B: null

此日志中的一个下拉菜单标记为“a”,并有一个标记为“B”的子菜单,其中包含我的 firebase 应用程序项目。我想知道我是否应该找到可以遍历所有这些下拉菜单以使身份验证工具工作的东西?

最终 - 尝试这个并没有太大区别 - 一旦 firebase 方法开始,表单仍然挂起并且什么都不做......但它记录了一个不同的值,我想知道是否弄清楚所有发生了什么这些下拉菜单是通向救赎的途径吗?如果是这样,找出所有字母和首字母缩写词含义的关键在哪里?

handleCreate = () => {
      console.log(this.formRef);
      const { form } = this.formRef.props;
      form.validateFields((err, values) => {
        if (err) {
          console.log(err);
          return;
        }

        console.log("Received values of form: ", values);
        const { email, password } = values;
        // console.log(Firebase)
        // console.log(this.form.props.firebase)
        // console.log(this.formRef.props)
        console.log("check before firebase", this.props.firebase.auth)
        this.props.firebase
          // .auth
          .auth()
          .doCreateUserWithEmailAndPassword(values.email, values.password)
          .console.log("try to check if create worked", values.email)
          .then(authUser => {
            console.log("logging user", { authUser });
            this.setState({ ...initialValues });
            this.props.history.push(DASHBOARD);
          })
          .catch(error => {
            this.setState({ error });
          });
          form.resetFields();
            this.setState({ visible: false });
            this.props.history.push(DASHBOARD);
        // form.resetFields();
        // this.setState({ visible: false });
      });
      // form.preventDefault();
    };

下一次尝试

此尝试尝试使用 .set 而不是 .add

它仍然返回一个错误,上面写着:

M {code: "auth/argument-error", message: “createUserWithEmailAndPassword 失败:第一个参数“email”必须是 一个有效的字符串。"}

handleCreate = event => {
                const { name, email, password } = this.state;
          console.log(this.props.firebase)
                this.props.firebase
                  .doCreateUserWithEmailAndPassword(email, password)
                  .then(authUser => {

                    return this.props.firebase.user(authUser.user.uid).set(
                      {
                        name,
                        email,

                      },
                      { merge: true },
                    );
                  })
                //   .then(() => {
                //     return this.props.firebase.doSendEmailVerification();
                //   })
                  .then(() => {
                    this.setState({ ...initialValues });
                    this.props.history.push(ROUTES.DASHBOARD);
                  })
                  .catch(error => {

                  });
                event.preventDefault();
              };          

控制台日志的输出在我的配置中设置了整个 Firebase 类 - 以:

Firebase {doCreateUserWithEmailAndPassword: ƒ, doSignInWithEmailAndPassword: ƒ, doSignOut: ƒ, doPasswordReset: ƒ, doPasswordUpdate: ƒ, ...} auth: Km {l: false, settings: Al, app: FirebaseAppImpl, b: ni, O: Array(0), ...}

我尝试修改它以在 this.props.firebase 之后插入 .auth 和 .auth(),但它返回一个错误,指出这些不是函数。

在下一次尝试之前的无用的旁白:

我正试图找出表单中的值被调用,现在无法访问控制台日志。它给出了一条消息:

[HMR] 等待来自 WDS 的更新信号...

我将开始调查到底出了什么问题,以便接下来发生这种情况。

同时,这是下一次尝试:

handleCreate = event => {
    const { name, email, password } =  this.formRef.props.state;
    console.log(email)
    console.log(name)
    this.props.firebase
        .doCreateUserWithEmailAndPassword(this.state.email, this.state.password)
        .then(authUser => {

        return this.props.firebase.user(authUser.user.uid).set(
            {
            name: this.state.name,
            email: this.state.email,

            },
            { merge: true },
        );
        })
        .then(() => {
        this.setState({ ...initialValues });
        this.props.history.push(ROUTES.DASHBOARD);
        })
        .catch(error => {

        });

    event.preventDefault();
    };          

  saveFormRef = formRef => {
    this.formRef = formRef;
  };

似乎解决了之前的问题。新的错误消息说:

TypeError: 无法读取未定义的属性“名称”

我不知道这是前进还是倒退。但是在我弄清楚为什么我不能再使用控制台日志时,我暂停了这行查询。

下一次尝试

我试图弄清楚表单值被称为什么来弄清楚如何将它们提供给 firebase。

这些变体中的每一个都忽略了 console.logs,但每次尝试的错误消息都会有所不同。此尝试会生成一条错误消息:

TypeError: 无法读取未定义的属性“名称”

handleCreate = event => {
    const  name =  this.formRef.props.getFieldValue.name;
    const  email =  this.formRef.props.email;
    const  password =  this.formRef.props.password;
    console.log(this.formRef.props.getFieldValue.email);
    console.log(this.form.props.getFieldValue.email);
    console.log(this.formRef.props.getFieldValue.name);
    this.props.firebase
        .doCreateUserWithEmailAndPassword(email, password)
        .then(authUser => {

        return this.props.firebase.user(authUser.user.uid).set(
            {
            name: this.formRef.props.getFieldValue.name,
            email: email,

            },
            { merge: true },
        );
        })
        .then(() => {
        this.setState({ ...initialValues });
        this.props.history.push(ROUTES.DASHBOARD);
        })
        .catch(error => {

        });

    event.preventDefault();
    };          

【问题讨论】:

  • 显然this.state.email 不是有效的字符串值。您可能想在调用doCreateUserWithEmailAndPassword 之前console.log(email) 以查看确实 包含什么值。
  • 就是这样 - 所有的 console.log 条目都以未定义的形式返回。我在定义它的 const 下开始的每一行都放置了一个 console.log(email) 。第一个返回一个错误,上面写着:TypeError:无法读取未定义的属性“电子邮件”,其余的被忽略。我找不到如何找到它的定义位置。
  • 我觉得跟firebase没什么关系,你用的是ant design form,从外观上看,有些不像文档里的。 ant.design/components/form
  • @Doppio - 是的 - AntDesign,适合使用教程。当数据库是实时数据库并且没有身份验证时,它工作正常。它发布了一个在用户表中创建用户的表单。现在,适应是添加firebase auth并移动到cloud firestore - 我找不到如何找到电子邮件的价值

标签: reactjs firebase firebase-authentication


【解决方案1】:

终于。

句柄提交是这样的:

handleCreate = () => {
    const { form } = this.formRef.props;
    form.validateFields((err, values) => {
      if (err) {
        return;
      };
    const payload = {
    // ...values,
    name: values.name,
    email: values.email,
     // createdAt: Firebase.FieldValue.serverTimestamp()
    }
    console.log("formvalues", payload);

    this.props.firebase
    .doCreateUserWithEmailAndPassword(values.email, values.password)
    .then(authUser => {
    return this.props.firebase.user(authUser.user.uid).set(
        {
        name: values.name,
        email: values.email,
        },
        { merge: true },
    );
    })
    // .then(docRef => {
    //     resetForm(initialValues);
    // })
    .then(e => this.setState({ modalShow: true }))


    form.resetFields();
    this.setState({ visible: false });
    this.props.history.push(DASHBOARD);

  });

    };

  saveFormRef = formRef => {
    this.formRef = formRef;
  };

  render() {
    return (
      <React.Fragment>
          <Button type="primary" onClick={this.showModal} >
            GET STARTED
          </Button>

            <CollectionCreateForm
              wrappedComponentRef={this.saveFormRef}
              visible={this.state.visible}
              onCancel={this.handleCancel}
              onCreate={this.handleCreate}
            />


      </React.Fragment>
    );
  };
}

firebase 配置如下:

user = uid => this.db.doc(`users/${uid}`);

提交处理程序中仍然存在问题 - 它会创建此通知,但我之前已经看到过,并且当我发现如何停止查看表单中的更改时会更新此答案。

警告:无法对未安装的组件执行 React 状态更新。 这是一个空操作,但它表明您的应用程序中存在内存泄漏。 要修复,取消所有订阅和异步任务 componentWillUnmount 方法。

【讨论】:

    【解决方案2】:

    通常我会建议在Form 上使用onSubmit 道具

    但在你的情况下,要避免改变太多。 您可以通过

    访问表单的当前值

    this.props.form.getFieldsValue()this.props.form.validateFields(); 如果您想先验证。

    // Change your handleCreate in RegisterBase  to accept values as first parameter
    handleCreate = (values) => {
      // const {  email, password } = values;
      const {  email, password } = values;
    }
    
    const CollectionCreateForm = Form.create({ name: 'form_in_modal' })(
      // eslint-disable-next-line
      class extends React.Component {
    
        handleCreate = e => {
          e.preventDefault();
          this.props.form.validateFields((err, values) => {
            if (!err) {
              console.log('Received values of form: ', values);
              // Get email, password from form values... 
              // key is the one you use in getFieldDecorator 
              const { email, password } = values;
              this.props.onCreate(values); 
            }
    
          });
        }
    
        render() {
    
          const { visible, onCancel, form } = this.props;
          const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched } = form;
          const passwordError = isFieldTouched('password') && getFieldError('password');
    
          return (
            <Modal
              visible={visible}
              title="Register"
              okText="Submit"
              onCancel={onCancel}
              onOk={this.handleCreate}
            >
              <Form layout="vertical">
    
                <Form.Item label="Name">
                  {getFieldDecorator('name', {
                    rules: [{ required: true, message: 'Your full name' }],
                  })(<Input />)}
                </Form.Item>
                <Form.Item label="Password" validateStatus={passwordError ? 'error' : ''} help={passwordError || ''}>
                  {getFieldDecorator('password', {
                    rules: [{ required: true, message: 'Create a password' }],
                  })(
                    <Input
                      type="password"
                      placeholder="Minimum 6 characters"
                    />,
                  )}
                </Form.Item>
                <Form.Item label="Email">
                  {getFieldDecorator('email', {
                    rules: [{ required: true, message: 'Your email address' }],
                  })(<Input />)}
                </Form.Item>
                <Form.Item label="Select your role">
                  {getFieldDecorator('role', {
                    initialValue: 'test',
                  })(
                    <Radio.Group>
                      <Radio value="test1">1</Radio>
                      <Radio value="test2">2 R&D</Radio>
                    </Radio.Group>,
                  )}
                </Form.Item>
    
              </Form>
            </Modal>
          );
        }
      },
    );
    

    【讨论】:

    • 感谢您的建议。我尝试将 handleSubmit 移动到表单 - 它不会生成任何错误消息,但它也没有做任何事情 - 表单冻结并且模式只是锁定到位 - 没有提交。
    • 您的其他建议是我将提交处理程序留在我拥有的地方并像这样使用它来获取电子邮件值: const { email } = this.props.form.getFieldsValue().email ?我试过这个,但它会产生一个错误,上面写着:TypeError: Cannot read property 'getFieldsValue' of undefined
    • 哦,我没看到你把“提交”按钮放在哪里。现在我看到了,您将表单提交绑定到模态 isOk 道具。所以它冻结的原因是因为没有提交表单。我会更新我的答案。
    • 我将firebase方法放在哪一个handleCreate方法中?
    • 现在我有 2 个句柄创建方法,它们都没有 firebase 位
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-18
    • 1970-01-01
    • 2021-06-06
    • 2019-02-23
    • 1970-01-01
    相关资源
    最近更新 更多