使用来自 firebase 集合的键值对填充反应选择选项数组

Posted

技术标签:

【中文标题】使用来自 firebase 集合的键值对填充反应选择选项数组【英文标题】:Populate react select options array with key value pairs from firebase collection 【发布时间】:2019-09-23 00:54:47 【问题描述】:

我正在尝试在我的 react 应用程序中使用选项数组,该数组使用 react-select 作为表单以及选项存储在 firebase 集合中的位置。

当我使用键值对定义的一组选项在表单中定义一个 const 时,这一切都很好,但我正在努力弄清楚如何用存储在 Firebase 中的集合替换该数组(Cloud Firestore )。

在我的表格中,我目前有:

const options = [
   value: "neurosciences", label: "Neurosciences - ABS 1109" ,
   value: "oncologyCarcinogenesis", label: "Oncology and Carcinogenesis  - ABS 1112" ,
   value: "opticalPhysics", label: "Optical Physics  - ABS 0205" ,
   value: "fisheriesSciences", label: "Fisheries Sciences - ABS 0704" ,
   value: "genetics", label: "Genetics - ABS 0604" ,
   value: "urbanRegionalPlanning", label: "Urban and Regional Planning - ABS 1205" 
];

我想用数据库集合中文档标题的映射替换这个数组。

我数据库中的文档名称有键,每个文档都有一个名为“标题”的字段。

感谢在我的表单中选择我有:

<div className="form-group">
                            <label htmlFor="fieldOfResearch">
                            Select your field(s) of research
                            </label>

                            <Select
                            key=`my_unique_select_key__$fieldOfResearch`
                            name="fieldOfResearch"
                            isMulti
                            className=
                                "react-select-container" +
                                (errors.fieldOfResearch && touched.fieldOfResearch ? " is-invalid" : "")
                            
                            classNamePrefix="react-select"
                            value=this.state.selectedValue1
                            onChange=e => 
                                handleChange1(e);
                                this.handleSelectChange1(e);
                            
                            onBlur=setFieldTouched
                            options=options
                            />
                            errors.fieldOfResearch && touched.fieldOfResearch && 
                            <ErrorMessage
                            name="fieldOfResearch"
                            component="div"
                            className="invalid-feedback d-block"
                            />
                            </div>

我已经阅读了有关使用数组的 firebase 文档,但我遗漏了一些东西(可能很明显),导致我至少有 20 条不同的路径来了解如何做到这一点。

我不确定这是否相关,但我的表单是使用 Formik 构建的。

如何将 const 选项数组替换为 firebase 数据库集合中键值对的映射?

我试图将我的选项常量定义为:

const options = fsDB.collection("abs_for_codes")

但页面充满了我无法解读的错误。我已阅读此用户指南,但不了解与索引相关的说明,我什至不清楚它们是否是解决此问题需要了解的内容。

https://firebase.google.com/docs/firestore/query-data/queries

我也试过了:

const options = fsDB.collection("abs_for_codes").get().then(function (querySnapshot) 
    querySnapshot.forEach(function (doc))

但这只是试图理解文档的猜测。

当我尝试使用 firebase 文档中显示的确切公式时,如下所示:

const options = fsDB.collection("abs_for_codes");

options.get().then(function (querySnapshot) 
    querySnapshot.forEach(function (doc) 
        console.log(doc.id, ' => ', doc.data());
    );
);

我收到一整页难以理解的错误消息,如下所示:

TypeError: options.reduce is not a function
Select.buildMenuOptions
node_modules/react-select/dist/react-select.esm.js:4123
  4120 |   ;
  4121 | ;
  4122 | 
> 4123 | return options.reduce(function (acc, item, itemIndex) 
       | ^  4124 |   if (item.options) 
  4125 |     // TODO needs a tidier implementation
  4126 |     if (!_this3.hasGroups) _this3.hasGroups = true;
View compiled
new Select
node_modules/react-select/dist/react-select.esm.js:3593
  3590 | 
  3591 | var _selectValue = cleanValue(value);
  3592 | 
> 3593 | var _menuOptions = _this.buildMenuOptions(_props, _selectValue);
       | ^  3594 | 
  3595 | _this.state.menuOptions = _menuOptions;
  3596 | _this.state.selectValue = _selectValue;
View compiled
constructClassInstance
node_modules/react-dom/cjs/react-dom.development.js:11787
  11784 |     new ctor(props, context); // eslint-disable-line no-new
  11785 |   
  11786 | 
> 11787 | var instance = new ctor(props, context);
        | ^  11788 | var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null;
  11789 | adoptClassInstance(workInProgress, instance);
  11790 | 
View compiled
updateClassComponent
node_modules/react-dom/cjs/react-dom.development.js:15265
  15262 |    // In the initial pass we might need to construct the instance.
  15263 | 
  15264 | 
> 15265 |   constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime);
        | ^  15266 |   mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime);
  15267 |   shouldUpdate = true;
  15268 |  else if (current$$1 === null) 
View compiled
beginWork
node_modules/react-dom/cjs/react-dom.development.js:16265
  16262 | 
  16263 |     var _resolvedProps = workInProgress.elementType === _Component2 ? _unresolvedProps : resolveDefaultProps(_Component2, _unresolvedProps);
  16264 | 
> 16265 |     return updateClassComponent(current$$1, workInProgress, _Component2, _resolvedProps, renderExpirationTime);
        | ^  16266 |   
  16267 | 
  16268 | case HostRoot:
View compiled
performUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js:20285
  20282 |   startProfilerTimer(workInProgress);
  20283 | 
  20284 | 
> 20285 | next = beginWork(current$$1, workInProgress, nextRenderExpirationTime);
        | ^  20286 | workInProgress.memoizedProps = workInProgress.pendingProps;
  20287 | 
  20288 | if (workInProgress.mode & ProfileMode) 
View compiled
workLoop
node_modules/react-dom/cjs/react-dom.development.js:20326
  20323 | if (!isYieldy) 
  20324 |   // Flush work without yielding
  20325 |   while (nextUnitOfWork !== null) 
> 20326 |     nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
        | ^  20327 |   
  20328 |  else 
  20329 |   // Flush asynchronous work until there's a higher priority event
View compiled
HTMLUnknownElement.callCallback
node_modules/react-dom/cjs/react-dom.development.js:147
  144 |     window.event = windowEvent;
  145 |   
  146 | 
> 147 |   func.apply(context, funcArgs);
      | ^  148 |   didError = false;
  149 |  // Create a global error event handler. We use this to capture the value
  150 | // that was thrown. It's possible that this error handler will fire more
View compiled
invokeGuardedCallbackDev
node_modules/react-dom/cjs/react-dom.development.js:196
  193 | // errors, it will trigger our global error handler.
  194 | 
  195 | evt.initEvent(evtType, false, false);
> 196 | fakeNode.dispatchEvent(evt);
      | ^  197 | 
  198 | if (windowEventDescriptor) 
  199 |   Object.defineProperty(window, 'event', windowEventDescriptor);
View compiled
invokeGuardedCallback
node_modules/react-dom/cjs/react-dom.development.js:250
  247 | function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) 
  248 |   hasError = false;
  249 |   caughtError = null;
> 250 |   invokeGuardedCallbackImpl$1.apply(reporter, arguments);
      | ^  251 | 
  252 | /**
  253 |  * Same as invokeGuardedCallback, but instead of returning an error, it stores
View compiled
replayUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js:19509
  19506 | 
  19507 | isReplayingFailedUnitOfWork = true;
  19508 | originalReplayError = thrownValue;
> 19509 | invokeGuardedCallback(null, workLoop, null, isYieldy);
        | ^  19510 | isReplayingFailedUnitOfWork = false;
  19511 | originalReplayError = null;
  19512 | 
View compiled
renderRoot
node_modules/react-dom/cjs/react-dom.development.js:20439
  20436 | if (true && replayFailedUnitOfWorkWithInvokeGuardedCallback) 
  20437 |   if (mayReplay) 
  20438 |     var failedUnitOfWork = nextUnitOfWork;
> 20439 |     replayUnitOfWork(failedUnitOfWork, thrownValue, isYieldy);
        | ^  20440 |   
  20441 |  // TODO: we already know this isn't true in some cases.
  20442 | // At least this shows a nicer error message until we figure out the cause.
View compiled
performWorkOnRoot
node_modules/react-dom/cjs/react-dom.development.js:21363
  21360 |   cancelTimeout(timeoutHandle);
  21361 | 
  21362 | 
> 21363 | renderRoot(root, isYieldy);
        | ^  21364 | finishedWork = root.finishedWork;
  21365 | 
  21366 | if (finishedWork !== null) 
View compiled

另一个尝试:

const options = abs_for_codes.map((title) => 
    <option key=title
    value=id />

这也不起作用 - 我尝试了它,因为它看起来类似于反应数组指令。

附图显示了firestore中的数据结构。

下一次尝试

按照默里的建议,我试过了

import Select from "react-select";
import  fsDB, firebase, settings  from "../../../firebase";

let options = [];

const initialValues = 
  fieldOfResearch: null,




class ProjectForm extends React.Component 
  state = 
    selectedValue1: options,


handleSelectChange1 = selectedValue1 => 
    this.setState( selectedValue1 );
  ;


componentDidMount() 
    fsDB.collection("abs_for_codes").get().then(function (querySnapshot) 
        let newOptions = [];
        querySnapshot.forEach(function (doc) 
            console.log(doc.id, ' => ', doc.data());
            newOptions.push(
              value: doc.data().title.replace(/( )/g, ''),
              label: doc.data().title + ' - ABS ' + doc.id
            );
        );
        this.setState(options: newOptions);
    );



handleSubmit = (formState,  resetForm ) => 
    // Now, you're getting form state here!
    console.log("SUCCESS!! :-)\n\n", formState);
    fsDB
      .collection("project")
      .add(formState)
      .then(docRef => 
        console.log("docRef>>>", docRef);
        this.setState( selectedValue1: null );
        this.setState( selectedValue2: null );
        this.setState( selectedValue3: null );
        this.setState( selectedValue4: null );
        this.setState( selectedValue5: null );
        this.setState( selectedValue6: null );

        resetForm(initialValues);
      )
      .catch(error => 
        console.error("Error adding document: ", error);
      );
  ;


onSubmit=this.handleSubmit
        render=( errors, status, touched, setFieldTouched, handleSubmit, values ) => 
          let fieldOfResearch;
          const handleChange1 = optionsObject => 
            fieldOfResearch = optionsObject;
            return (values.fieldOfResearch = optionsObject.value);
          ;

<div className="form-group">
                                <label htmlFor="fieldOfResearch">
                                Select your field(s) of research
                                </label>

                                <Select
                                key=
`my_unique_select_key__$fieldOfResearch`
                                name="fieldOfResearch"
                                isMulti
                                className=
                                    "react-select-container" +
                                    (errors.fieldOfResearch && touched.fieldOfResearch ? " is-invalid" : "")
                                
                                classNamePrefix="react-select"
                                value=this.state.selectedValue1
                                onChange=e => 
                                    handleChange1(e);
                                    this.handleSelectChange1(e);
                                
                                onBlur=setFieldTouched
                                options=options
                                />
                                errors.fieldOfResearch && touched.fieldOfResearch && 
                                <ErrorMessage
                                name="fieldOfResearch"
                                component="div"
                                className="invalid-feedback d-block"
                                />
                                </div>

因此,单步执行,options 从一个空数组开始,ComponentDidMount 函数将其状态重置为 NewOptions 并输入到表单选择下拉列表中。

这一切对我来说都很有意义,但它不起作用 - 我只是得到一个空数组。

当我尝试 Avanthika 的建议时,我可以呈现表单,并且可以从正确的 db 集合中选择多个选项,但是当我提交表单时没有任何反应。 react 中的控制台调试器显示出一张不笑的脸(我以前从未见过。下图)。当我删除选择字段时,此表单提交正常。

下一次尝试

当我尝试以下 Murray R 和 Avinthika 的更新建议时,我可以选择多个字段。但我无法提交表格。如果我删除选择字段,则表单提交。提交formik多字段表单有技巧吗?

我的提交按钮是:

<div className="form-group">
                <Button
                  variant="outline-primary"
                  type="submit"
                  style=style3
                  id="ProjectId"
                  onClick=handleSubmit
                  disabled=!dirty || isSubmitting

                >
                  Save
                </Button>
              </div>

我的句柄提交有:

handleSubmit = (formState,  resetForm ) => 
    // Now, you're getting form state here!
    console.log("SUCCESS!! :-)\n\n", formState);
    fsDB
      .collection("project")
      .add(
          ...(formState),
          createdAt: firebase.firestore.FieldValue.serverTimestamp()
      )
      .then(docRef => 
        console.log("docRef>>>", docRef);
        this.setState( selectedValue1: null, selectedValue2: null, selectedValue3: null, selectedValue4: null, selectedValue5: null, selectedValue6: null );

        // this.setState( selectedValue1: null );
        // this.setState( selectedValue2: null );
        // this.setState( selectedValue3: null );
        // this.setState( selectedValue4: null );
        // this.setState( selectedValue5: null );
        // this.setState( selectedValue6: null );

        resetForm(initialValues);
      )
      .catch(error => 
        console.error("Error adding document: ", error);
      );
  ;

控制台不记录任何内容。

下一次尝试

我删除并重新安装了 react chrome 扩展程序,它又可以正常工作了。

附加的屏幕截图显示表单未验证且未提交,但每个表单值的状态都在其中 - 您可以看到截图底部显示表单字段值之一为“ s'。

进一步尝试

所以 - 我将这个表单拆分为一个只有一个字段的表单 - 我一直在这里尝试处理的选择字段。

整个表格有:

import React from 'react';

import  Formik, Form, Field, ErrorMessage, withFormik  from "formik";
import * as Yup from "yup";
import Select from "react-select";
import  fsDB, firebase, settings  from "../../../firebase";

import 
    Badge,
    Button,
    Col,
    ComponentClass,
    Feedback,
    FormControl,
    FormGroup,
    FormLabel,
    InputGroup,
    Table,
    Row,
    Container
   from "react-bootstrap";

const initialValues = 
    fieldOfResearch: null,



class ProjectForm extends React.Component 
    state = 
      options: [],  
      selectedValue1: [],
    

    async componentDidMount() 
            // const fsDB = firebase.firestore(); // Don't worry about this line if it comes from your config.
            let options = [];
            await fsDB.collection("abs_for_codes").get().then(function (querySnapshot) 
            querySnapshot.forEach(function(doc) 
                console.log(doc.id, ' => ', doc.data());
                options.push(
                  value: doc.data().title.replace(/( )/g, ''),
                  label: doc.data().title + ' - ABS ' + doc.id
                );
              );
            );
            this.setState(
              options
            );
          


  handleSelectChange1 = selectedValue1 => 
    this.setState( selectedValue1 );
  ;

  handleSubmit = (formState,  resetForm ) => 
    // Now, you're getting form state here!
    console.log("SUCCESS!! :-)\n\n", formState);
    fsDB
      .collection("project")
      .add(
          ...(formState),
          createdAt: firebase.firestore.FieldValue.serverTimestamp()
      )
      .then(docRef => 
        console.log("docRef>>>", docRef);
        this.setState( selectedValue1: null);


        resetForm(initialValues);
      )
      .catch(error => 
        console.error("Error adding document: ", error);
      );
  ;

  render() 
    const  options  = this.state;  
    return (
      <Formik
        initialValues=initialValues
        validationSchema=Yup.object().shape(
          //   fieldOfResearch: Yup.array().required("What is your field of research?"),
        )

        onSubmit=this.handleSubmit
        render=( errors, status, touched, setFieldTouched, handleSubmit, isSubmitting, dirty, values ) => 
          let fieldOfResearch;
          const handleChange1 = optionsObject => 
            fieldOfResearch = optionsObject;
            return (values.fieldOfResearch = optionsObject.value);
          ;
          return (
            <div>
            <Form>
                <div className="form-group">

                                <label htmlFor="fieldOfResearch">
                                Select your field(s) of research
                                </label>
                                <Select
                                    key=`my_unique_select_key__$fieldOfResearch`
                                    name="fieldOfResearch"
                                    isMulti
                                    className=
                                        "react-select-container" +
                                        (errors.fieldOfResearch && touched.fieldOfResearch
                                        ? " is-invalid"
                                        : "")
                                    
                                    classNamePrefix="react-select"
                                    value=this.state.selectedValue1
                                    onChange=e => 
                                        handleChange1(e);
                                        this.handleSelectChange1(e);
                                    
                                    onBlur=setFieldTouched
                                    options=options
                                    />    

                                errors.fieldOfResearch && touched.fieldOfResearch && 
                                <ErrorMessage
                                name="fieldOfResearch"
                                component="div"
                                className="invalid-feedback d-block"
                                />
                                </div> 
                                <div className="form-group">
                                <Button
                                  variant="outline-primary"
                                  type="submit"
                                  id="ProjectId"
                                  onClick=handleSubmit
                                //   disabled=!dirty || isSubmitting

                                >
                                  Save
                                </Button>
                              </div>
                              </Form>

            </div>
        );
    
  />
);



export default ProjectForm;

此表格允许在表格中选择研究领域。 on submit 函数在控制台中工作,在某种程度上它使用 fieldOfResearch 将成功记录为“未定义”。数据库中没有任何内容。

错误消息说:未处理的拒绝(FirebaseError):函数 使用无效数据调用 DocumentReference.set()。不支持的字段 值:未定义(在字段 fieldOfResearch 中找到)▶

当我尝试输入字段值并检查反应值时,错误消息显示:

未捕获的类型错误:无法将 undefined 或 null 转换为对象

【问题讨论】:

不知道为什么有人提议对我的问题进行修改以更改我在选择菜单中使用的标签或响应选择为下拉菜单提供的类名 来自您的数据库集合的数据是什么样的? 我不知道你的问题是什么意思。数据库中有一个名为 abs_for_codes 的集合。该集合中的每个文档都有一个名为“title”的属性。每个文档的名称是一个数字(例如 1109),对应的标题是“Neurosciences” ` const options = fsDB.collection("abs_for_codes"); options.get().then(function (querySnapshot) querySnapshot.forEach(function (doc) console.log(doc.id, '=>', doc.data()); ); ); ` 当你尝试这个时,它在控制台上显示什么?你能复制粘贴控制台消息吗? 嗨@Mel,我为你付出了额外的努力,我已经设置了所有内容,创建了一个包含文档的集合并尝试了你的代码。我已经在答案中分享了有效的 sn-p - 看看它并让我知道它是否有效。 【参考方案1】:

另一个更新的答案:

错误消息说:未处理的拒绝(FirebaseError):函数 使用无效数据调用 DocumentReference.set()。不支持的字段 值:未定义(在字段 fieldOfResearch 中找到

发生此错误是因为您的表单值无效。您没有保持正确的 formik 状态。

我刚刚尝试过并检查过,表单提交对我来说非常有用。你写了太多多余的代码——我们只需要原生的 formik 方法和 firebase。变更日志如下:

    react-select 的 onChange 应该使用 Formik 中的 setFieldValue,如下所示:
onChange=selectedOptions => 
   // Setting field value - name of the field and values chosen.
   setFieldValue("fieldOfResearch", selectedOptions)

    初始值应该是一个空数组。由于我们声明了 initialValues 并通过 Formik 维护了表单值,因此绝对不需要内部状态管理。即,不需要this.state.selectedValue1handleChange1handleSelectChange1。如果您查看 Formik HOC 的 render(),您会注意到 values - 这会在每次更改后给出表单的当前值。

所以,

value=this.state.selectedValue1

应该改为

value=values.fieldOfResearch
    我已经像这样编写了 handleSubmit - 您的代码的精确副本。但我只是从选定选项数组中提取值:
handleSubmit = (formState,  resetForm ) => 
  // Now, you're getting form state here!
  const fdb = firebase.firestore();
  const payload = 
    ...formState,
    fieldOfResearch: formState.fieldOfResearch.map(t => t.value)
  
  console.log("formvalues", payload);
  fdb
  .collection("project")
  .add(payload)
  .then(docRef => 
    console.log("docRef>>>", docRef);
    resetForm(initialValues);
  )
  .catch(error => 
    console.error("Error adding document: ", error);
  );

我可以在控制台中看到表单提交和 docRef。表单也会重置为初始状态。

import React from "react";
import  Formik, Form, ErrorMessage  from "formik";
import * as Yup from "yup";
import Select from "react-select";
import firebase from "./firebase";
import 
  Button,
  Container
 from "react-bootstrap";

const initialValues = 
  fieldOfResearch: []
;

class App extends React.Component 
  constructor(props) 
    super(props);
    this.state = 
      options: []
    ;
  

  async componentWillMount() 
    const fdb = firebase.firestore();
    let options = [];
    await fdb
      .collection("abs_codes")
      .get()
      .then(function(querySnapshot) 
        querySnapshot.forEach(function(doc) 
          options.push(
            value: doc.data().title.replace(/( )/g, ""),
            label: doc.data().title
          );
        );
      );
    this.setState(
      options
    );
  

  handleSubmit = (formState,  resetForm ) => 
    // Now, you're getting form state here!
    const fdb = firebase.firestore();
    const payload = 
      ...formState,
      fieldOfResearch: formState.fieldOfResearch.map(t => t.value)
    
    console.log("formvalues", payload);
    fdb
    .collection("project")
    .add(payload)
    .then(docRef => 
      console.log("docRef>>>", docRef);
      resetForm(initialValues);
    )
    .catch(error => 
      console.error("Error adding document: ", error);
    );
  

  render() 
    const  options  = this.state;
    return (
      <Container>
        <Formik
          initialValues=initialValues
          validationSchema=Yup.object().shape(
              fieldOfResearch: Yup.array().required("What is your field of research?"),
          )
          onSubmit=this.handleSubmit
          render=(
            errors,
            status,
            touched,
            setFieldValue,
            setFieldTouched,
            handleSubmit,
            isSubmitting,
            dirty,
            values
          ) => 
            return (
              <div>
                <Form>
                  <div className="form-group">
                    <label htmlFor="fieldOfResearch">
                      Select your field(s) of research
                    </label>
                    <Select
                      key=`my_unique_select_keyfieldOfResearch`
                      name="fieldOfResearch"
                      isMulti
                      className=
                        "react-select-container" +
                        (errors.fieldOfResearch && touched.fieldOfResearch
                          ? " is-invalid"
                          : "")
                      
                      classNamePrefix="react-select"
                      value=values.fieldOfResearch
                      onChange=selectedOptions => 
                        setFieldValue("fieldOfResearch", selectedOptions)
                      
                      onBlur=setFieldTouched
                      options=options
                    />
                    errors.fieldOfResearch && touched.fieldOfResearch &&
                      <ErrorMessage
                         name="fieldOfResearch"
                         component="div"
                         className="invalid-feedback d-block"
                      />
                    
                  </div>
                  <div className="form-group">
                    <Button
                      variant="outline-primary"
                      type="submit"
                      id="ProjectId"
                      onClick=handleSubmit
                      disabled=!dirty || isSubmitting
                    >
                      Save
                    </Button>
                  </div>
                </Form>
              </div>
            );
          
        />
      </Container>
    );
  


export default App;

先尝试复制粘贴,然后再尝试进行更改。我想这应该对你有帮助!


更新答案:

嗨,梅尔,我只是将整个事情都设置在我的系统中并尝试为你做这件事,虽然我无法与你分享信用,但我想这应该会有所帮助。

    javascript 不同步。您的 componentDidMount 不会等待您尝试从 firebase 获取的数据。它只会在您的查询返回响应之前设置状态。

    他们的关键是等待响应。我以这种方式编辑了代码,并且可以在控制台上的 render() 中看到选项。

import React from 'react';
import firebase from "./firebase.js";

class App extends React.Component 
  constructor(props) 
    super(props);
    this.state = 
      options: []
    
  

  async componentDidMount() 
    const fsDB = firebase.firestore(); // Don't worry about this line if it comes from your config.
    let options = [];
    await fsDB.collection("abs_for_codes").get().then(function (querySnapshot) 
    querySnapshot.forEach(function(doc) 
        console.log(doc.id, ' => ', doc.data());
        options.push(
          value: doc.data().title.replace(/( )/g, ''),
          label: doc.data().title
        );
      );
    );
    this.setState(
      options
    );
  

  render() 
    console.log(this.state);
    const  options  = this.state;
    return (
      <div className="form-group">
        <label htmlFor="fieldOfResearch">
          Select your field(s) of research
        </label>

        <Select
          key=`my_unique_select_key__$fieldOfResearch`
          name="fieldOfResearch"
          isMulti
          className=
            "react-select-container" +
            (errors.fieldOfResearch && touched.fieldOfResearch
              ? " is-invalid"
              : "")
          
          classNamePrefix="react-select"
          value=this.state.selectedValue1
          onChange=e => 
            handleChange1(e);
            this.handleSelectChange1(e);
          
          onBlur=setFieldTouched
          options=options
        />
      </div>
    );
  


export default App;

让我知道这是否适合你!

我不禁注意到,为什么handleSubmit 中有这么多setState?你强迫你的组件重新渲染很多次。相反,您可以这样做:

handleSubmit = (formState,  resetForm ) => 
    // Now, you're getting form state here!
    console.log("SUCCESS!! :-)\n\n", formState);
    fsDB
      .collection("project")
      .add(formState)
      .then(docRef => 
        console.log("docRef>>>", docRef);
        this.setState( selectedValue1: null, selectedValue2: null, selectedValue3: null, selectedValue4: null, selectedValue5: null, selectedValue6: null );
        resetForm(initialValues);
      )
      .catch(error => 
        console.error("Error adding document: ", error);
      );
  ;

【讨论】:

嗨 - firebase 表称为“abs_codes”。它有一组记录,每条记录都保存为一个数字(即:0704),其文档有一个名为标题的字段:(即渔业科学)。在我的表单中,我想使用该集合,以便将其中的文档用作选项。 我不想定义一个名为 firebaseData 的 const - 并列出每个数据库条目,我只想弄清楚如何将集合用作表单中的数组。 无论如何-我尝试使用您的建议的想法,但它会抛出一个错误,说 map 不是 firebase 中的函数 实际上 - 我现在正在调试它。它越来越近了。仍然无法正常工作,但会引发新的错误。我现在必须去开会,但今晚会继续努力。感谢您的帮助 谢谢。我在选择表单中的键表达式也错误。这行得通。非常感谢!【参考方案2】:

若要在从 Firestore 检索您的研究领域后更新您的 React 组件,您需要声明您的 options,以便 React 关注其值的变化。您可以通过在类的状态中保存选项并稍后使用setState() 更新它来做到这一点:

// At the top of the class,
state = 
  options: [],
  // Any other state properties,
;

然后,在 componentDidMount() 函数中,调用您的 Firestore 集合并使用结果填充 state.options

fsDB.collection("abs_for_codes").get().then(function (querySnapshot) 
    let newOptions = [];
    querySnapshot.forEach(function (doc) 
        console.log(doc.id, ' => ', doc.data());
        newOptions.push(
          value: doc.data().title.replace(/( )/g, ''),
          label: doc.data().title + ' - ABS ' + doc.id
        );
    );
    setState(options: newOptions);
);

这应该会从 Firestore 中检索您的“abs_for_codes”文档,并将它们分配给您的组件的 options 属性,以允许您的 Select 元素填充新数据。

【讨论】:

抱歉,我刚刚从其他解释您的 Firestore 收藏的答案中注意到您的 cmets。鉴于该信息,将我的答案中的语句更改为:``` newOptions.push( value: doc.data().title, label: doc.data().title + ' - ABS ' + doc.id ) ; ``` 我不遵循这个,但我尝试了你的建议。我必须在函数中声明 let 语句,但是当我这样做时,构造中至少有 6 个错误。我解决了第一批,但不想继续调试此代码以查看其中是否有有用的东西。我也不明白上面关于标签的评论。它可能是某事的简写,但我不够聪明,无法弄清楚。无论如何感谢您的帮助。 我更新了我的答案以反映基于类的 React 组件示例。 嗨默里 - 我试过这个。我没有收到任何错误,但我只得到一个空数组 - 它没有填充 Firestore 数据。我已经在上面发布了当前的表单数据。 嗨,梅尔,删除顶部的 let options = []; 语句。您需要将options 声明为类组件state 的一部分,以便您的React 表单知道对其值的变化做出“反应”。为此,请修改您的state = 分配以包括options: []。 (我调整了我的答案以反映您的示例。)当 componentDidMount() 中的 Firestore 调用运行时,它通过使用新检索/构建的 newOptions 数组更新 state.options 来完成。并且,在您的表单中,您需要更新 options=this.state.options,以便它引用您检索到的选项。【参考方案3】:

那么这样的东西会有帮助吗?

function SomeComponentName(props) 
  const [options, setOptions] = React.useState([]);

  React.useEffect(() => 
    getOptions()
  , []

  async function getOptions() 
    const tmpArr = [];

    try 
      // Perform get() request and loop through all docs
      await fsDB
        .collection("abs_codes")
        .get()
        .then(snapshot => 
          snapshot.forEach(doc => 
            const  title  = doc.data();
            const label = `$title - ABS $doc.key`;

            tmpArr.push( value: title, label );
          );
          setOptions(tmpArr);
        );
     catch (err) 
      console.log("Error getting documents", err);
    
  

  return (
    <div className="form-group">
      <label>
        <Select
          // ...
          options=options
          // ...
        />
      </label>
    </div>
  );

这将获取“abs_code”集合中的所有文档,遍历它们,并将每个条目作为一个对象推送到“选项”数组。

【讨论】:

为什么选项数组是空的?您是否建议我将您的 absCodesRef 包含在 const 选项或表单中?如果是后者,您建议使用 options 数组做什么? 选项数组只是由该语句创建,因为它将由下一个代码填充。当您调用“absCodeRef.get()...”时,forEach 循环将获取每个文档,使用标签/值创建对象,并将其推送到“选项”数组。 您需要在 React 组件挂载时(或在您需要渲染 Select 之前)调用 absCodeRef.get() 函数,因为它随后在 Select 中用于创建每个选项.这有意义吗? 不确定如何使用您的建议。我按原样尝试过,但反应不接受。无论如何,谢谢,但我没有时间尝试学习你的思维方式来弄清楚这是否会有所帮助 对不起 - 不,我不明白你的意思。我会继续寻找解决方案

以上是关于使用来自 firebase 集合的键值对填充反应选择选项数组的主要内容,如果未能解决你的问题,请参考以下文章

根据指定的键从集合中创建键值对集合

map集合中的键值对对象遍历

在 React JS 中显示来自 Json 的键值对

观察 NSMutableSet 的键值对

使用Javascript拆分由“&”分隔的键值对响应[重复]

Go语言 遍历map中的键值对