Заполните массив опций реагирования и выбора парами значений ключей из коллекции Firebase - PullRequest
5 голосов
/ 05 мая 2019

Я пытаюсь использовать массив опций в моем приложении реагирования, которое использует реакцию-выбор для формы и где опции хранятся в коллекции 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" }
];

Я хочу заменить этот массив картой названий документов в коллекции базы данных.

Имя документа в моей базе данных имеет ключ, и у каждого документа есть одно поле с названием «title».

Спасибо, что в моей форме выберите:

<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>

Я прочитал документы по использованию массивов, но мне не хватает чего-то (вероятно, очевидного), которое привело меня по крайней мере к 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.

data structure

СЛЕДУЮЩАЯ ПОПЫТКА

Используя предложение Мюррея, я попытался

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>

Итак, пошагово, что параметры начинаются как пустой массив, функция ComponentDidMount сбрасывает свое состояние в NewOptions, и это вводится в выпадающий список выбора формы.

Это все имеет смысл для меня, но это не работает - я просто получаю пустой массив.

Когда я пытаюсь предложить предложение Авантики, я могу отобразить форму, и можно выбрать несколько вариантов из правой коллекции БД, но ничего не происходит, когда я отправляю форму. Консольный отладчик в реакции показывает неулыбчивое лицо (я никогда раньше такого не видел. Рис ниже). Эта форма отправляется нормально, когда я удаляю поле выбора.

enter image description here

следующая попытка

когда я пробую каждое из обновленных предложений 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);
      });
  };

Консоль ничего не регистрирует.

следующая попытка

Я удалил и заново установил расширение реагирования Chrome, и оно снова работает.

Прикрепленный снимок экрана показывает, что форма не проверяется и не отправляется, но там находится состояние каждого из значений формы - вы можете увидеть в нижней части снимка одно из значений поля формы в виде ' s'.

enter image description here

дальнейшая попытка

Итак, я разделил эту форму на форму, в которой есть только одно поле - поле выбора, над которым я пытался работать.

Эта форма в целом имеет:

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 как «undefined». В базе данных ничего не сохраняется.

Сообщение об ошибке гласит: необработанный отказ (FirebaseError): функция DocumentReference.set () вызван с неверными данными. Неподдерживаемое поле значение: не определено (находится в поле fieldOfResearch) ▶

Когда я пытаюсь ввести значение поля и проверить значение реакции, появляется сообщение об ошибке:

Uncaught TypeError: Невозможно преобразовать неопределенный или нулевой объект

Ответы [ 3 ]

3 голосов
/ 08 мая 2019

Еще один обновленный ответ:

Сообщение об ошибке гласит: необработанный отказ (FirebaseError): функция DocumentReference.set () вызван с неверными данными. Неподдерживаемое поле значение: не определено (найдено в поле fieldOfResearch

Эта ошибка произошла из-за недопустимых значений формы. Вы не поддерживаете правильное состояние formik.

Я только что попробовал это и проверил, форма отправки отлично работает для меня. Вы написали слишком много лишнего кода - нам просто нужны нативные методы formik и firebase. Журнал изменений выглядит следующим образом:

  1. OnChange реакции-выбора должен использовать setFieldValue из Formik следующим образом:
onChange={selectedOptions => {
   // Setting field value - name of the field and values chosen.
   setFieldValue("fieldOfResearch", selectedOptions)}
}
  1. Начальное значение должно быть пустым массивом. Поскольку мы объявили initialValues ​​и поддерживаемые через Formik значения форм, абсолютно нет необходимости во внутреннем управлении состоянием. То есть, нет необходимости в this.state.selectedValue1, handleChange1 и handleSelectChange1. Если вы посмотрите на render () вашего Formik HOC, вы заметите values - Это дает текущее значение формы после каждого изменения.

Итак,

value={this.state.selectedValue1}

следует изменить на

value={values.fieldOfResearch}
  1. Я написал 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;

Просто попробуйте сначала скопировать этот код, а поверх этого попробуйте внести изменения. Я думаю, это должно быть полезно для вас!


Обновленный ответ:

Привет, Мел, я просто установил все это в своей системе и попытался сделать это для тебя, хотя я не могу поделиться с тобой кредитами, думаю, это должно помочь.

  1. Javascript не является синхронным. Ваш componentDidMount не будет ждать данных, которые вы пытаетесь получить из firebase. Он просто установит состояние, прежде чем ваш запрос вернет ответ.

  2. Они должны дождаться ответа. Я отредактировал код таким образом, и я могу видеть опции на моей консоли в 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;

Дайте мне знать, если это работает для вас!

И я не мог не заметить, почему так много setStates в handleSubmit? Вы заставляете свой компонент перерисовывать это много раз. Вместо этого вы можете сделать:

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);
      });
  };

1 голос
/ 13 мая 2019

Чтобы ваш компонент React обновлялся после извлечения ваших исследовательских полей из Firestore, вам нужно объявить свой 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});
});

Это должно извлечь ваши документы 'abs_for_codes' из Firestore и назначить их свойству options вашего компонента таким образом, чтобы ваш элемент Select мог быть заполнен новыми данными.

1 голос
/ 08 мая 2019

Так что-то вроде этой помощи?

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», пройти через них и отправить каждую запись как объект в массив «options».

...