I'm trying to figure out how to use react-firebase-hooks in my react app so that I can simplify calls on my database.
My previous version (solved with help on this question) of this attempt used this class component with a componentDidMount function (it worked):
class Form extends React.Component {
    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 + ' - ABS ' + doc.id
            });
            });
        });
        this.setState({
            options
        });
    }
I'm now trying to learn how to use hooks to get the data from the database using react-firebase-hooks. My current attempt is:
import { useDocumentOnce } from 'react-firebase-hooks/firestore';
I have also tried import { useDocument } from 'react-firebase-hooks/firestore';
const [snapshot, loading, error] = useDocumentOnce(
  firebase.firestore().collection('abs_for_codes'),
  options.push({
    value: doc.data().title.replace(/( )/g, ''),
    label: doc.data().title + ' - ABS ' + doc.id
  }),
);
This generates an error that says: 'useDocumentOnce' is not defined
I tried (that's also incorrect):
const [snapshot, loading, error] = useDocumentOnce(
  firebase.firestore().collection('abs_for_codes'),
  {snapshot.push({
    value: doc.data().title.replace(/( )/g, ''),
    label: doc.data().title + ' - ABS ' + doc.id,
  })},
);
How do I get a collection from firebase? I'm trying to populate a select menu with the options read from a collection in firebase called abs_for_codes.
I think the point of useState is that I don't need to declare a state anymore, I can just call I have added my select attempt below:
<Select 
            className="reactSelect"
            name="field"
            placeholder="Select at least one"
            value={valuesSnapshot.selectedOption}
            options={snapshot}
            onChange={handleMultiChangeSnapshot}
            isMulti
            ref={register}
          />
For reference, I have 2 other select menus in my form. The consts I use to set up the options for those are manually defined, but the process to establish their values is below:
const GeneralTest = props => {
  const { register, handleSubmit, setValue, errors, reset } = useForm();
  const { action } = useStateMachine(updateAction);
  const onSubit = data => {
    action(data);
    props.history.push("./ProposalMethod");
  };
  const [valuesStudyType, setStudyType] = useState({
    selectedOptionStudyType: []
  });
  const [valuesFundingBody, setFundingBody] = useState({
    selectedOptionFundingBody: []
  });
  const handleMultiChangeStudyType = selectedOption => {
    setValue("studyType", selectedOption);
    setStudyType({ selectedOption });
  };
  const handleMultiChangeFundingBody = selectedOption => {
    setValue("fundingBody", selectedOption);
    setFundingBody({ selectedOption });
  };
  useEffect(() => {
    register({ name: "studyType" });
    register({name: "fundingBody"});
  }, []);
How do I add the snapshot from the database query?
I have tried making similar handleMultiChange const and useEffect register statements for the snapshot, like so:
  const [snapshot, loading, error] = useDocumentOnce(
    firebase.firestore().collection('abs_for_codes'),
    snapshot.push({
      value: snapshot.data().title.replace(/( )/g, ''),
      label: snapshot.data().title + ' - ABS ' + snapshot.id
    }),
  );
  const [valuesField, setField ] = useState({
    selectedOptionField: []
  });
  const handleMultiChangeField = selectedOption => {
    setValue("field", selectedOption);
    setField({ selectedOption });
  };
but it doesn't work. The error message says:
ReferenceError: Cannot access 'snapshot' before initialization
I can't find an example of how to populate the select menu with the data from the database.
NEXT ATTEMPT
useEffect(
    () => {
      const unsubscribe = firebase
        .firestore()
        .collection('abs_for_codes')
        .onSnapshot(
          snapshot => {
            const fields = []
            snapshot.forEach(doc => {
              fields.push({
                value: fields.data().title.replace(/( )/g, ''),
                label: fields.data().title + ' - ABS ' + fields.id
              })
            })
            setLoading(false)
            setFields(fields)
          },
          err => {
            setError(err)
          }
        )
      return () => unsubscribe()
    })
This doesn't work either - it produces an error message that says:
TypeError: fields.data is not a function
NEXT ATTEMPT
Recognising that i need to search the collection rather than a call on document, but still not sure whether useCollectionData is more appropriate than useCollectionOnce (I can't make sense of the documentation about what useCollectionData offers), I have now tried:
const [value, loading, error] = useCollectionOnce(
  firebase.firestore().collection('abs_for_codes'),
  {getOptions({
    firebase.firestore.getOptions:
    value: doc.data().title.replace(/( )/g, ''),
    label: doc.data().title + ' - ABS ' + doc.id,
  })},
);
This is also incorrect. The error message points to the getOptions line and says: Parsing error: Unexpected token, expected ","
In my collection, i have a number of documents. Each has 2 attributes, a number and a text string. My options are to format the number and the text string so they appear together as well as an acronym i have inserted as text (as I was able to do using componentDidMount).
NEXT ATTEMPT
I next tried this:
const fields = firebase.firestore.collection("abs_for_codes").get().then(function(querySnapshot) {
  querySnapshot.forEach(function(doc) {
    console.log(doc.id, ' => ', doc.data());
    fields.push({
        value: doc.data().title.replace(/( )/g, ''),
        label: doc.data().title + ' - ABS ' + doc.id
    });
    });
});
The error message says: TypeError: _firebase__WEBPACK_IMPORTED_MODULE_5__.firebase.firestore.collection is not a function
NEXT ATTEPMT
const searchFieldOfResearchesOptions = (searchKey, resolver) => {
    // for more info
    // https://stackoverflow.com/questions/38618953/how-to-do-a-simple-search-in-string-in-firebase-database
    // https://firebase.google.com/docs/database/rest/retrieve-data#range-queries
    fsDB
      .collection("abs_for_codes")
      .orderBy("title")
      // search by key
      .startAt(searchKey)
      .endAt(searchKey + "\uf8ff")
      .onSnapshot(({ docs }) => {
        // map data to react-select
        resolver(
          docs.map(doc => {
            const { title } = doc.data();
            return {
              // value: doc.id,
              // label: title
              value: title.data().title.replace(/( )/g, ''),
              label: title.data().title + ' - ABS ' + title.id
            };
          })
        );
      }, setFieldOfResearchesError);
  };
This attempt actually works to retrieve data from the database (hooray) - except I can't get the text label I want to render. Each document in the collection has 2 fields. The first is a title and the second is an id number, my last step is to make a label that has inserted text (ie ABS - ) and then the id number and the title together.
I have added the commented code to show what works to extract each document's title, but the extra bit I tried to make the label the way I want it doesn't present an error, it just doesn't work - I still only get the document title in the list.
Does anyone know how to generate a select menu set of options from a cloud firestore collection using hooks?


