user14232549
user14232549

Reputation: 413

How to get a sub collection with firestoreConnect in React-redux project - Cloud Firebase

I am learning to react-redux-firebase with the tutorial below.

I added sub-collection to collection. However, I don't know how to fetch subcollection. I need to get the original collection and its subcollection.

tutorial: https://github.com/iamshaunjp/React-Redux-Firebase-App/blob/lesson-20/marioplan/src/components/projects/ProjectDetails.js

const mapStateToProps = (state, ownProps) => {
    const id = ownProps.match.params.id;
    const projects = state.firestore.data.projects;
    const project = projects ? projects[id] : null
    const subproject = //?
}

export default compose(
    connect(mapStateToProps),
    firestoreConnect([
        { collection: 'projects',
        collection: 'subprojects'
    }
    ])
)(ProjectDetails);

I would like to use this enter image description here

not enter image description here

Upvotes: 1

Views: 497

Answers (1)

rustyBucketBay
rustyBucketBay

Reputation: 4551

Edited answer:

I dont post all the steps here, but you need to follow the exact same steps you did with the projects collection, but for your subprojects collection, so make your subprojects reducer, add that to the rootReducer...etc, so that the subprojects are in the global state, and you can link those to your component, the same as you did with the projects collection.

You would need to define if it will be in a separated reducer, in the project reducer itself so that it will figure in the state like this: const subprojects = state.firestore.data.projects.subprojects;

To compose your connector, you need to check redux-firestore repo where its adviced how to connect subcollections. Check the exmaple:

{
  collection: 'cities',
  doc: 'SF',
  subcollections: [{ collection: 'zipcodes' }],
  storeAs: 'SF-zipcodes' // make sure to include this
},

So that said, the mapStateToProps would be as below:

const mapStateToProps = (state, ownProps) => {
  // console.log(state);
  const id = ownProps.match.params.id;
  const subprojects = state.firestore.data.projects.subprojects;
  const subproject = subproject ? subproject [id] : null
  return {
    subproject : subproject 
  }
}

export default compose(
  connect(mapStateToProps),
  firestoreConnect([{
    collection: 'projects',
    doc: 'YourDoc'
    subcollections: [{ collection: 'subprojects' }],
    storeAs: 'YorDoc-subprojects'
  }])
)(YourSubProjectsComponent)

Not debugged code, just a proposal based on the repo example in case it might be helpfull for you to move on.

On the other hand I case if it is of any help, find below the code of the projectDetails compenent, fetching the determined project from the firestore with the useState hook. For your specific case, I believe that it would apply the same way, but querying your subprojects collection. (typescript code). I post this, just in case you might be after a 'manual' fetch of your collection, instead of the direct binding with redux. If what you want is the direct bind with redux of your subproject collection you just can ommit the code below.

import { IFirebaseProject } from '../../store/types/projectTypes';
import { Redirect } from 'react-router-dom';
import moment from 'moment';
import firebase from 'firebase/app';
import { useState } from 'react'; 

async function getFbProject(id: string) {
  const db = firebase.firestore();
  const fbDoc = db.collection("projects").doc(id);
  let project = {} as IFirebaseProject;
  await fbDoc.get().then(function(doc) {
      if (doc.exists) {
          console.log("Document data:", doc.data());
          project = { ...doc.data()} as IFirebaseProject;
      } else {
          console.log(`Document does not exist ${id}`);
      }
  }).catch(function(error) {
      console.log(`Error getting document: ${id}`, error);
  });

  return project;
}

function getProjectId():string {
  const pathStr = window.location.pathname.toString();
  const parts = pathStr.split("/");
  const projStrIndex = parts.indexOf('project');
  const projectId = parts[projStrIndex + 1];
  return projectId;
}

const ProjectDetails = ({ project }: { project: IFirebaseProject } | { project: undefined }) => {
  const [stateProject, setStateProject] = useState<IFirebaseProject | undefined>(project);
  if (!firebase.auth().currentUser) return <Redirect to='/'/>
  if (stateProject) {
    return(
      <div className="container section project-details">
        <div className="card z-depth-0">
          <div className="card-content">
            <span className="card-title">{stateProject.title}</span>
            <p>
              {stateProject.content}
            </p>
          </div>
          <div className="card-action grey lighten-4">
            <div>{stateProject.authorFirstName} {stateProject.authorLastName}</div>
            <div>{moment(stateProject.createdAt.toDate()).calendar()}</div>
          </div>
        </div>
      </div>
    )
  } else {
    //fetch project
    const projectId = getProjectId();
    getFbProject(projectId).then((project) => { 
      if (project) {
        setStateProject(project);
      }
    });

    return(
      <div>
        <p> Loading project... </p>
      </div>
    )
  }
}

export default ProjectDetails;

Upvotes: 1

Related Questions