How to get subcollection from firestore using react-redux-firebase - reactjs

I am not able to get the sub-collection from my Firestore data.
I followed the documentation here. And also looked at many other similar question on this.
I can't seem to get the array of data that i want to get.
My code:
import "../../styles/projects/ProjectDashboard.css";
import ProjectList from "./ProjectList";
import { connect } from "react-redux";
import { firestoreConnect } from "react-redux-firebase";
import { compose } from "redux";
import { Redirect } from "react-router-dom";
export class ProjectDashboard extends Component {
render() {
const { projects, auth } = this.props;
if (!auth.uid) return <Redirect to="/sigin" />;
return (
<div className="container">
<h2>Projects</h2>
<ProjectList projects={projects} />
</div>
);
}
}
const mapStateToProps = state => {
console.log(state);
return {
projects: state.firestore.ordered.projects,
auth: state.firebase.auth
};
};
export default compose(
connect(mapStateToProps),
firestoreConnect(props => {
return [
{
collection: "users",
doc: props.auth.uid,
subcollection: [{ collection: "projects" }]
}
];
})
)(ProjectDashboard);
this is what i am getting now from my console :
firestore:
|-composite: undefined
|-data: {users: {…}}
|-errors: {byQuery: {…}, allIds: Array(0)}
|-listeners: {byId: {…}, allIds: Array(1)}
|-ordered:
|--users: Array(1)
|---0: {id: "o06VEyRbGDcURTmKal3gDEDZQO73", firstName: "testing", lastName: "you", userId: "o06VEyRbGDcURTmKal3gDEDZQO73"}
|---length: 1
|---__proto__: Array(0)
|--__proto__: Object
|-queries: {}
|-status: {requesting: {…}, requested: {…}, timestamps: {…}}
|-__proto__: Object
I was thinking that my code will change this part:
|-ordered:
|--users: Array(1)
|---0: {id: "o06VEyRbGDcURTmKal3gDEDZQO73", firstName: "testing", lastName: "you", userId: "o06VEyRbGDcURTmKal3gDEDZQO73"}
to something like this:
|-ordered:
|--projects: Array(3)
|---0: {id: "o06VEyRbGDcURTmKal3gDEDZQO73", firstName: "testing", lastName: "you", userId: "o06VEyRbGDcURTmKal3gDEDZQO73"}
|---1: {id: "o06VEyRbGDcURTmKal3gDEDZQO73", firstName: "testing", lastName: "you", userId: "o06VEyRbGDcURTmKal3gDEDZQO73"}
|---2: {id: "o06VEyRbGDcURTmKal3gDEDZQO73", firstName: "testing", lastName: "you", userId: "o06VEyRbGDcURTmKal3gDEDZQO73"}
so i can get the array through the key. But now i am at a lost on how to change it into my sub-collection key.

I realised that it should be "subcollections" and not "subcollection"

Related

Why I get undefined when I use react redux RTK query useByIdQuery

I created store where are a all endpoints and I have a issues with getById endpoint.
Store.tsx
import { createApi, fetchBaseQuery } from "#reduxjs/toolkit/query/react";
import { Character } from "../interface/types";
export const characterAPI = createApi({
reducerPath: "characterAPI",
baseQuery: fetchBaseQuery({ baseUrl: "https://www.breakingbadapi.com/api/" }),
tagTypes: ["Characters"],
endpoints: (builder) => ({
getAll: builder.query<Character[], void>({
query: () => `characters`,
providesTags: [{ type: "Characters", id: "LIST" }],
}),
getById: builder.query<Character, string>({
query: (char_id) => `characters/${char_id}`,
providesTags: [{ type: "Characters", id: "LIST" }],
}),
}),
});
CharacterContainer.tsx
But after loading I can see whole data, but when i wanna console.log(getById) its's says undefined
import React from "react";
import { useParams } from "react-router-dom";
import { characterAPI } from "../store/store";
const CharacterContainer = () => {
const { char_id } = useParams();
const { data: getById, isLoading } = characterAPI.useGetByIdQuery(
char_id as string
);
console.log(getById);
const { name, birthday } = getById || {};
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
<p>{name}</p>
<p>{birthday}</p>
</div>
);
};
And what I see in tools:
CharacterContainer.tsx:22 undefined
CharacterContainer.tsx:22 undefined
CharacterContainer.tsx:22
[{…}]0: appearance: (5) [1, 2, 3, 4, 5]
better_call_saul_appearance: []
birthday: "09-07-1958"
category: "Breaking Bad"
char_id: 1
img: "https://images.amcnetworks.com/amc.com/wpcontent/uploads/2015/04/cast_bb_700x1000_walter-white-lg.jpg"
name: "Walter White"
nickname: "Heisenberg"
occupation: (2)
['High School Chemistry Teacher', 'Meth King Pin']
portrayed: "Bryan Cranston"status:
"Presumed dead"[[Prototype]]: Objectlength: 1[[Prototype]]: Array(0)
This is because you are trying to console.log the result immediately, and this means you are trying to output getById when the query is still in it's loading phase. You could do something like:
console.log(isLoading ? "Loading result" : getById)
Your output would then be something like:
CharacterContainer.tsx:22 undefined
CharacterContainer.tsx:22 undefined
CharacterContainer.tsx:22
[{…}]0: appearance: (5) [1, 2, 3, 4, 5]
better_call_saul_appearance: []
birthday: "09-07-1958"
category: "Breaking Bad"
char_id: 1
img: "https://images.amcnetworks.com/amc.com/wpcontent/uploads/2015/04/cast_bb_700x1000_walter-white-lg.jpg"
name: "Walter White"
nickname: "Heisenberg"
occupation: (2)
['High School Chemistry Teacher', 'Meth King Pin']
portrayed: "Bryan Cranston"status:
"Presumed dead"[[Prototype]]: Objectlength: 1[[Prototype]]: Array(0)

Map array from another api endpoint and pass through prop of React child component

I need to pass responses from two APIs, i.e. hobbies and person API, to my child component. So I am able to map() the child component and show the data in a list.
The response from person api:
{[
0: {id: 01, name: {…}, familyName: {…}, phone: 0 …}
1: {id: 02, name: {…}, familyName: {…}, phone: 0 …}
2: {id: 03, name: {…}, familyName: {…}, phone: 0 …}
3: {id: 04, name: {…}, familyName: {…}, phone: 0 …}
4: {id: 05, name: {…}, familyName: {…}, phone: 0 …}
5: {id: 06, name: {…}, familyName: {…}, phone: 0 …}
6: {id: 07, name: {…}, familyName: {…}, phone: 0 …}
]
}
The response from hobbies api:
{ data: {
name: "Test name"
hobbies: (2) [{…}, {…}]
userId: "test"
_id: "4767647478"
}
}
The component:
const PersonList = () => {
const [loading, setLoading] = useState(false);
const [persons, setPersons] = useState<Person[]>([]);
const [hobbies, setHobbies] = useState<Hobbies[]>([]);
const urls = [
"https://person-api",
"https://hobbies-api",
];
const getData = async () => {
setLoading(true);
const [result1, result2] = await Promise.all(
urls.map((url) => fetch(url).then((res) => res.json()))
);
setLoading(false);
setPersons(result1);
setHobbies(result2);
};
useEffect(() => {
getData();
}, []);
return (
<div>
<div>
{persons.map((person) => {
return (
<PersonCard
key={person.id}
name={person.name}
/>
);
})}
</div>
</div>
);
};
export default PersonList;
The above code works fine and renders a list of names of the persons. But how do I map() and pass the hobbies (from different api response) with a prop e.g. hobbies through my child component,like below?
<PersonCard
key={person.id}
name={person.name}
hobbies={hobby.name}
/>

Which reducer gets used when using dispatch in mapDispatchToProps? [duplicate]

This question already has answers here:
All reducers will be invoked when an action is dispatched?
(3 answers)
Closed 2 years ago.
I am learning about Redux and I have two reducers, a contactReducer to show contacts on the page and a testReducer to just mess around with. In one of my component files I have this function:
const mapDispatchToProps = (dispatch) => ({
getContacts: () => dispatch({ type: "TEST_ACTION" }),
});
These are my two reducer files:
contactReducer:
import { GET_CONTACTS } from "../actions/types";
const initialState = {
contacts: [
{
id: 1,
name: "John Doe",
email: "john#gmail.com",
phone: "555-555-5555",
},
{
id: 2,
name: "Karen Williams",
email: "karen#gmail.com",
phone: "444-444-4444",
},
{
id: 3,
name: "Henry Johnson",
email: "henry#gmail.com",
phone: "333-333-333",
},
],
};
export default function (state = initialState, action) {
switch (action.type) {
case GET_CONTACTS:
return {
...state,
};
default:
console.log("testing action in contactReducer");
return state;
}
}
and testReducer:
import { GET_CONTACTS } from "../actions/types";
const initialState = {
contactsTest: [
{
id: 1,
name: "ffffffffffff",
email: "john#gmail.com",
phone: "555-555-5555",
},
{
id: 2,
name: "ggggggggggggg",
email: "karen#gmail.com",
phone: "444-444-4444",
},
{
id: 3,
name: "aaaaaaaaaaaaaa",
email: "henry#gmail.com",
phone: "333-333-333",
},
],
};
export default function (state = initialState, action) {
switch (action.type) {
case "TEST_ACTION":
return {
...state,
};
default:
console.log("testing action");
return state;
}
}
So, what I noticed from the console.log statements in the reducer files was that for every contact, both the contactReducer and testReducer's function was called with this line:
getContacts: () => dispatch({ type: "TEST_ACTION" }),
});
What if I have multiple reducers but I only want to call one of their functions for dispatch, what would I do?
combineReducers, Is a helper function in redux that helps you divide your reducers. take a look at this link: LINK

Cannot read property 'map' of undefined when looking at an array with no index

Just a thanks in advance for any help and for the tremendous resource this place has been before now. This is my first time asking a question and I'm still a bit of a newbie so please forgive anything obvious that I'm missing.
I have a created an API out of an Postgresql database using node. That is working fine my queries.js file is below.
const Pool = require('pg').Pool
const pool = new Pool({
user: 'user',
host: 'localhost',
database: 'database',
password: 'password',
port: 5432,
});
const tableThree = (request, response) => {
pool.query('SELECT * FROM t3_0 ORDER BY time DESC LIMIT 10', (error, results) => {
if (error) {
throw error
}
response.status(200).json(results.rows)
})
}
module.exports = {
tableThree,
}
This gets passed along to my index.js file....
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const cors = require('cors');
const db = require('./queries')
const port = 3001
app.use(bodyParser.json())
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(cors());
app.get('/', (request, response) => {
response.json({ info: 'Node.js, Express, and Postgres API' })
});
app.get('/table3', db.tableThree);
app.listen(port, () => {
console.log(`App running on port ${port}.`)
});
which creates an api where I can view the information from my postgresql database.
From my angular project I import it as a service...
import { Injectable } from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class simulatorService {
constructor(private http: HttpClient) {
}
tableThree() {
return this.http.get("http://localhost:3001/table3")
.pipe(map(result => result));
}
}
I updated my app.module.ts file so the service could be used...
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { simulatorService } from './esim06.service';
import { HttpClientModule } from '#angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [simulatorService],
bootstrap: [AppComponent]
})
export class AppModule { }
then in the app.components.ts file I bring in the service and I am able to see the expected data.
import { Component } from '#angular/core';
import { simulatorService } from './esim06.service';
import { Chart } from 'chart.js';
import { map } from 'rxjs/operators/map';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
chart = [];
constructor(private simulator: simulatorService) {}
ngOnInit() {
this.simulator.tableThree()
.subscribe(res => {
console.log(res)
//let i13 = res['list'] || [].map(res => res.i13);
//let alldates = res['list'] || [].map(res => res.i2)
let i13 = res[''].map(res => res.i13);
let alldates = res[''].map(res => res.i2)
let dates = []
alldates.forEach((res) => {
let jsdate = new Date(res)
dates.push(jsdate.toLocaleTimeString('en', { year: 'numeric', month: 'short', day: 'numeric' }))
})
console.log(dates)
console.log(i13)
this.chart = new Chart('canvas', {
type: 'line',
data: {
labels: alldates,
datasets: [
{
data: i13,
borderColor: '#3cba9f',
fill: false
},
//{
// data: acquireSun,
// borderColor: '#3cba9f',
// fill: false
//},
]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
display: true
}],
yAxes: [{
display: true
}]
}
}
})
});
}
}
For the first console.log(res) I can view the data in the inspector....
(10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {id: "4097", time: "2019-03-16T04:06:38.728Z", ple_id: "177550", meta_id: "1", reduced_id: null, …}
1: {id: "4094", time: "2019-03-16T04:06:31.710Z", ple_id: "177422", meta_id: "1", reduced_id: null, …}
2: {id: "4095", time: "2019-03-16T04:06:30.923Z", ple_id: "177404", meta_id: "1", reduced_id: null, …}
3: {id: "4096", time: "2019-03-16T04:06:28.333Z", ple_id: "177360", meta_id: "1", reduced_id: null, …}
4: {id: "4093", time: "2019-03-16T04:06:25.074Z", ple_id: "177292", meta_id: "1", reduced_id: null, …}
5: {id: "4090", time: "2019-03-16T04:06:22.743Z", ple_id: "177248", meta_id: "1", reduced_id: null, …}
6: {id: "4091", time: "2019-03-16T04:06:21.822Z", ple_id: "177230", meta_id: "1", reduced_id: null, …}
7: {id: "4092", time: "2019-03-16T04:06:19.356Z", ple_id: "177186", meta_id: "1", reduced_id: null, …}
8: {id: "4088", time: "2019-03-16T04:06:16.093Z", ple_id: "177118", meta_id: "1", reduced_id: null, …}
9: {id: "4089", time: "2019-03-16T04:06:13.648Z", ple_id: "177074", meta_id: "1", reduced_id: null, …}
length: 10
However, when I attempt to reference specific parts of the array through statements such as..
let i13 = res[''].map(res => res.i13);
let alldates = res[''].map(res => res.i2);
I get the following error..
core.js:14597 ERROR TypeError: Cannot read property 'map' of undefined
at SafeSubscriber._next (app.component.ts:25)
at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub (Subscriber.js:194)
at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next (Subscriber.js:132)
at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next (Subscriber.js:76)
at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:53)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:41)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:53)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:41)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:53)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/operators/filter.js.FilterSubscriber._next (filter.js:38)
I believe this is happening because the name of the array is undefined. so I cant write something like..
let i13 = res['list'].map(res => res.i13);
but I don't know how to either force it to accept it as undefined or give the array an index. Any help on this would be appreciated!
Thanks!
Going to throw out an answer based on our comment discussion, it will be easier to explain where your issue is.
What is being returned in the parameter 'res' is an array. Arrays have a access to a method called map. Map takes a function, and will call the function once for each value in the array and overall return a new array with the return values of map.
ie:
var res = [{ username: 'jsmith', firstname: 'John' }, { username: 'jdoe', firstname:' Jane" }];
var newArray = res.map(user => user.firstname);
console.log(newArray) // ['John', 'Jane']
Based on the mapping function, the first name will be grabbed from each object in the array, and a new array with those values will be created.
Arrays can also be accessed by integer index.
So:
var john = res[0];
console.log(john) // { username: 'jsmith', firstname: 'John' }
So in your case, you can just do res.map and you would get a each value one by one handed to that callback, and you could process them. Alternatively, you could access the elements by index res[0].id for example.
you can not do res[0].map , because the object stored in the first spot of the response is not an array

React redux not updating component when adding to array

So no matter what I do I can't get the component to refresh when I add a item to an array in the redux store.
What I use in my reducer to add to the redux state:
case ADD_NOTE_META:
return [
...state,
action.note,
];
The connector:
import { connect } from 'react-redux';
import NoteSection from './NoteSection.component';
const mapStateToProps = state => ({
notes: state.NotesMeta,
});
const mapDispatchToProps = () => ({});
export default connect(
mapStateToProps,
mapDispatchToProps,
)(NoteSection);
The component:
import React from 'react';
import PropTypes from 'prop-types';
import NoteSelectorContainer from './noteselector/NoteSelector.connector';
import DeleteConfirmationMessage from './deletenoteconfirmationmessage/DeleteConfirmationMessage.connector';
function NoteSection(props) {
const { notes } = props;
return (
<div id="divSelectNoteContainer">
{notes.map(item => (
<NoteSelectorContainer
note={item}
key={item.id}
/>
))}
<DeleteConfirmationMessage />
</div>
);
}
NoteSection.defaultProps = {
notes: [],
};
NoteSection.propTypes = {
notes: PropTypes.array,
};
export default NoteSection;
The state in redux is structured like:
{
NotesMeta: [
{
id: '5b6cd6c49a46d',
title: 'folder note',
tags: [
'test'
],
parentid: '5b6cd6c49a48d'
},
{
id: '5b6cd6c496ad2',
title: 'test note',
tags: [],
parentid: null
},
]
}
Output of console.log(notes) before add new note is run:
0: {id: "5b6cd6c49a46d", title: "folder note", tags: Array(1), parentid: "5b6cd6c49a48d"}
1: {id: "5b6cd6c496ad2", title: "test note", tags: Array(0), parentid: null}
After:
0: {id: "5b6cd6c49a46d", title: "folder note", tags: Array(1), parentid: "5b6cd6c49a48d"}
1: {id: "5b6cd6c496ad2", title: "test note", tags: Array(0), parentid: null}
2: {id: "5bb48aaae94c1", title: "New Note Title", tags: Array(0)}
I can see that the new note is added in both the redux store and the Notesection props however a new NoteSelectorContainer is never created.

Resources