onEndReached FlatList React Native - node.js

i currently have a FlatList in my React Native project that renders the posts from nodejs backend. I have applied the pagination to my backend and it is working when i am testing it on postman. My problem is when i test my app on a simulator when i reach the end of the page 0, page 1 does not load.
Here is my FlatList:
<FlatList
data={posts} // to have all the data
keyExtractor={(post) => post.id.toString()}
renderItem={({ item }) => (
<PostCard
title={item.title}
subTitle={item.subTitle}
/>
)}
onEndReached={onScrollHandler}
onEndThreshold={0}
/>
const { data: posts, error, loading, request: loadPosts } = useApi(
postsApi.getPosts
);
useEffect(() => {
loadPosts();
}, []);
const[page,setPage]=useState(0);
const[profiles,setProfiles]=useState([]);
const fetchRecords=(page)=>{
const newRecords = []
for(var i = page * 10, il = i + 10; i < il && i < posts.length; i++){
newRecords.push(posts[i]);
}
setProfiles(...profiles, ...newRecords)
}
const onScrollHandler =()=>{
setPage(page+1);
fetchRecords(page)
}
Here is my nodeJS backend:
router.get("/",
async (req, res) => {
const getPagination = (page, size) => {
const limit = size ? +size : 10;
const offset = page ? page * limit : 0;
return { limit, offset };
};
const { page, size } = req.query;
const { limit, offset } = getPagination(page, size);
const posts = await Post.findAll({
limit,offset,
Here my route is /posts which i declared in my index.js in my backend.
Before applying pagination in my backend, when i used to do console.log(posts) in frontend i used to get all my posts but after i applied pagination when i do console.log(posts) i only get the posts for the first page.

Can you try to put this in useEffect.
useEffect(()=>{ apiCall()},[page])

If I am not wrong, you want to concatenate newly fetched records with the records that you already have, if that is the case, then you are supposed to do it like below:
setProfiles([...profiles, ...newRecords])
example:
let str1 = [1,2,3,4]
let str2 = [5,6,7,7]
// you dont want that
console.log(...str1, ...str2)
// but this, it will create a new array,
// having elements of both str1 and str2 which is what should be
console.log([...str1, ...str2])
Example:
import React, { useState } from 'react';
import { Text, View, StyleSheet, FlatList } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default function App() {
const [posts, setPosts] = useState(
Array.from({ length: 10 }, () => Math.floor(Math.random() * 100))
);
const onEndReached = () => {
let newPosts = Array.from(
{ length: 4 },
() => 'New Item Added ' + Math.floor(Math.random() * 100)
);
console.log(newPosts)
setTimeout(() => {
setPosts([...posts, ...newPosts]);
}, 1000);
};
return (
<View style={styles.container}>
<FlatList
data={posts}
onEndReached={onEndReached}
keyExtractor={(posts) => Math.floor(Math.random() * 1000)}
renderItem={({ item }) => (
<Card style={styles.card}>
<Text style={styles.paragraph}>{item}</Text>
</Card>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
card: {
margin: 10,
padding: 10,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
Expo Demo
Screenshow:

Did you inspect if your onScrollHandler function is called whenever you reached at the end of the flat list.
Also please wrap your flat list inside SafeAreaView and give SafeAreaView style of flex : 1
<SafeAreaView>
<FlatList/>
</SafeAreaView>

Related

How to run mediapipe facemesh on a ES6 node.js environment alike react

I am trying to run this HTML example https://codepen.io/mediapipe/details/KKgVaPJ from https://google.github.io/mediapipe/solutions/face_mesh#javascript-solution-api in a create react application. I have already done:
npm install of all the facemesh mediapipe packages.
Already replaced the jsdelivr tags with node imports and I got the definitions and functions.
Replaced the video element with react-cam
I don't know how to replace this jsdelivr, maybe is affecting:
const faceMesh = new FaceMesh({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/#mediapipe/face_mesh/${file}`;
}
});
So the question is:
Why the facemesh is not showing? Is there any example of what I am trying to do?
This is my App.js code (sorry for the debugugging scaffolding):
import './App.css';
import React, { useState, useEffect } from "react";
import Webcam from "react-webcam";
import { Camera, CameraOptions } from '#mediapipe/camera_utils'
import {
FaceMesh,
FACEMESH_TESSELATION,
FACEMESH_RIGHT_EYE,
FACEMESH_LEFT_EYE,
FACEMESH_RIGHT_EYEBROW,
FACEMESH_LEFT_EYEBROW,
FACEMESH_FACE_OVAL,
FACEMESH_LIPS
} from '#mediapipe/face_mesh'
import { drawConnectors } from '#mediapipe/drawing_utils'
const videoConstraints = {
width: 1280,
height: 720,
facingMode: "user"
};
function App() {
const webcamRef = React.useRef(null);
const canvasReference = React.useRef(null);
const [cameraReady, setCameraReady] = useState(false);
let canvasCtx
let camera
const videoElement = document.getElementsByClassName('input_video')[0];
// const canvasElement = document.getElementsByClassName('output_canvas')[0];
const canvasElement = document.createElement('canvas');
console.log('canvasElement', canvasElement)
console.log('canvasCtx', canvasCtx)
useEffect(() => {
camera = new Camera(webcamRef.current, {
onFrame: async () => {
console.log('{send}',await faceMesh.send({ image: webcamRef.current.video }));
},
width: 1280,
height: 720
});
canvasCtx = canvasReference.current.getContext('2d');
camera.start();
console.log('canvasReference', canvasReference)
}, [cameraReady]);
function onResults(results) {
console.log('results')
canvasCtx.save();
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
canvasCtx.drawImage(
results.image, 0, 0, canvasElement.width, canvasElement.height);
if (results.multiFaceLandmarks) {
for (const landmarks of results.multiFaceLandmarks) {
drawConnectors(canvasCtx, landmarks, FACEMESH_TESSELATION, { color: '#C0C0C070', lineWidth: 1 });
drawConnectors(canvasCtx, landmarks, FACEMESH_RIGHT_EYE, { color: '#FF3030' });
drawConnectors(canvasCtx, landmarks, FACEMESH_RIGHT_EYEBROW, { color: '#FF3030' });
drawConnectors(canvasCtx, landmarks, FACEMESH_LEFT_EYE, { color: '#30FF30' });
drawConnectors(canvasCtx, landmarks, FACEMESH_LEFT_EYEBROW, { color: '#30FF30' });
drawConnectors(canvasCtx, landmarks, FACEMESH_FACE_OVAL, { color: '#E0E0E0' });
drawConnectors(canvasCtx, landmarks, FACEMESH_LIPS, { color: '#E0E0E0' });
}
}
canvasCtx.restore();
}
const faceMesh = new FaceMesh({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/#mediapipe/face_mesh/${file}`;
}
});
faceMesh.setOptions({
selfieMode: true,
maxNumFaces: 1,
minDetectionConfidence: 0.5,
minTrackingConfidence: 0.5
});
faceMesh.onResults(onResults);
// const camera = new Camera(webcamRef.current, {
// onFrame: async () => {
// await faceMesh.send({ image: videoElement });
// },
// width: 1280,
// height: 720
// });
// camera.start();
return (
<div className="App">
<Webcam
audio={false}
height={720}
ref={webcamRef}
screenshotFormat="image/jpeg"
width={1280}
videoConstraints={videoConstraints}
onUserMedia={() => {
console.log('webcamRef.current', webcamRef.current);
// navigator.mediaDevices
// .getUserMedia({ video: true })
// .then(stream => webcamRef.current.srcObject = stream)
// .catch(console.log);
setCameraReady(true)
}}
/>
<canvas
ref={canvasReference}
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zindex: 9,
width: 1280,
height: 720,
}}
/>
</div >
);
}
export default App;
You don't have to replace the jsdelivr, that piece of code is fine; also I think you need to reorder your code a little bit:
You should put the faceMesh initialization inside the useEffect, with [] as parameter; therefore, the algorithm will start when the page is rendered for the first time
Also, you don't need to get videoElement and canvasElement with doc.*, because you already have some refs defined
An example of code:
useEffect(() => {
const faceMesh = new FaceDetection({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/#mediapipe/face_detection/${file}`;
},
});
faceMesh.setOptions({
maxNumFaces: 1,
minDetectionConfidence: 0.5,
minTrackingConfidence: 0.5,
});
faceMesh.onResults(onResults);
if (
typeof webcamRef.current !== "undefined" &&
webcamRef.current !== null
) {
camera = new Camera(webcamRef.current.video, {
onFrame: async () => {
await faceMesh.send({ image: webcamRef.current.video });
},
width: 1280,
height: 720,
});
camera.start();
}
}, []);
Finally, in the onResults callback I would suggest printing first the results, just to check if the Mediapipe implementation is working fine. And don't forget to set the canvas size before drawing something.
function onResults(results){
console.log(results)
canvasCtx = canvasReference.current.getContext('2d')
canvas.width = webcamRef.current.video.videoWidth;
canvas.height = webcamRef.current.video.videoHeight;;
...
}
Good luck! :)

GSAP timeline needed on every page in Gatsby

My Gatsby site use the same GSAP timeline on every page, so I want to stay DRY and my idea is to include my timeline in my Layout component in that order.
But I don't know how to pass refs that I need between children and layout using forwardRef.
In short, I don't know how to handle the sectionsRef part between pages and layout.
sectionsRef is dependant of the page content (children) but is needed in the timeline living in layout.
How can I share sectionsRef between these two (I tried many things but always leading to errors)?
Here's a codesandbox without the refs in the Layout:
https://codesandbox.io/s/jolly-almeida-njt2e?file=/src/pages/index.js
And the sandbox with the refs in the layout:
https://codesandbox.io/s/pensive-varahamihira-tc45m?file=/src/pages/index.js
Here's a simplified version of my files :
Layout.js
export default function Layout({ children }) {
const containerRef = useRef(null);
const sectionsRef = useRef([]);
sectionsRef.current = [];
useEffect(() => {
gsap.registerPlugin(ScrollTrigger);
const scrollTimeline = gsap.timeline();
scrollTimeline.to(sectionsRef.current, {
x: () =>
`${-(
containerRef.current.scrollWidth -
document.documentElement.clientWidth
)}px`,
ease: 'none',
scrollTrigger: {
trigger: containerRef.current,
invalidateOnRefresh: true,
scrub: 0.5,
pin: true,
start: () => `top top`,
end: () =>
`+=${
containerRef.current.scrollWidth -
document.documentElement.clientWidth
}`,
},
});
}, [containerRef, sectionsRef]);
return (
<div className="slides-container" ref={containerRef}>
{children}
</div>
);
}
index.js (page)
import { graphql } from 'gatsby';
import React, { forwardRef } from 'react';
import SectionImage from '../components/sections/SectionImage';
import SectionIntro from '../components/sections/SectionIntro';
import SectionColumns from '../components/sections/SectionColumns';
const HomePage = ({ data: { home } }, sectionsRef) => {
const { sections } = home;
const addToRefs = (el) => {
if (el && !sectionsRef.current.includes(el)) {
sectionsRef.current.push(el);
}
};
return (
<>
{sections.map((section) => {
if (section.__typename === 'SanitySectionIntro') {
return (
<SectionIntro key={section.id} section={section} ref={addToRefs} />
);
}
if (section.__typename === 'SanitySectionImage') {
return (
<SectionImage key={section.id} section={section} ref={addToRefs} />
);
}
if (section.__typename === 'SanitySectionColumns') {
return (
<SectionColumns
key={section.id}
section={section}
ref={addToRefs}
/>
);
}
return '';
})}
</>
);
};
export default forwardRef(HomePage);
export const query = graphql`
query HomeQuery {
// ...
}
`;
Any clue greatly appreciated :)

How to use react native navigation wix with context to share data from provider to all components?

I want to use react-native-navigation with context to send data from provider to all my components. I have done it as follow:
index.js
import {Navigation} from 'react-native-navigation';
import {App} from './App'
App();
Navigation.events().registerAppLaunchedListener(() => {
Navigation.setRoot({
root: {
stack:
{
id: 'FoodApp',
children: [
{
component: {
id: 'myLoginId',
name: 'myLogin',
options: {
topBar: {
visible: false,
height: 0,
},
}
}
},
],
},
},
});
});
App.js
export const App = () => {
Navigation.registerComponent(`myLogin`, () => (props) => (
<GlobalProvider>
<Login {...props} />
</GlobalProvider>
), () => Login);
Navigation.registerComponent(`myMain`, () => (props) => (
<GlobalProvider>
<Main {...props} />
</GlobalProvider>
), () => Main);
};
GlobalProvider and GlobalContext
const GlobalContext = React.createContext();
export const GlobalProvider = ({children}) => {
return <GlobalContext.Provider value={20}>
{children}
</GlobalContext.Provider>;
};
export default GlobalContext;
Main.js
const Main = () => {
const value= useContext(GlobalContext);
const options = (passProps) => {
return {
topBar: {
height: 0,
},
};
};
return (
<View style={styles.mainContainer}>
<Text>Main {value}</Text>
</View>
);
};
It does not give any errors but it does not show value. Please help me how to fix it. I have searched a lot but I cannot find any useful thing.
I have used:
"react": "16.11.0",
"react-native": "0.62.0",
"react-native-navigation": "^6.3.3",
it's weird that the value is not showing at all as your code snippet should display value. I've created an example below to demonstrate integrating React Context with react-native-navigation but unfortunately as react-native-navigation is not a single root application (each registered screen is a "root") the regular Context pattern would not work as expected.
// CounterContext.js
import React from 'react
const initialCounterState = {
count: 0
}
const counterContextWrapper = (component) => ({
...initialCounterState,
increment: () => {
initialCounterState.count += 1
component.setState({ context: contextWrapper(component) })
},
decrement: () => {
initialCounterState.count -= 1
component.setState({ context: contextWrapper(component) })
},
})
export const CounterContext = React.createContext({})
export class CounterContextProvider extends React.Component {
state = {
context: counterContextWrapper(this)
}
render() {
return (
<CounterContext.Provider value={this.state.context}>
{this.props.children}
</CounterContext.Provider>
)
}
}
// index.js
import { Navigation } from 'react-native-navigation
import { CounterContextProvider } from './CounterContext
import { Main } from './Main
Navigation.registerComponent(
'Main',
() => props => (
<CounterContextProvider>
<Main {...props} />
</CounterContextProvider>
),
() => CounterReactContextScreen
)
// Main.js
import React from 'react'
import { Button, Text, View } from 'react-native'
import { CounterContext } from './CounterContext'
export const Main = () => {
const { count, increment, decrement } = React.useContext(CounterContext)
return (
<View>
<Text>{`Clicked ${count} times!`}</Text>
<Button title="Increment" onPress={increment} />
<Button title="Decrement" onPress={decrement} />
</View>
)
}
This should all work, however the caveat is if you register 2 screens with the same Context Provider (for example, Main as your root and Pushed as a screen that gets pushed from Main) if you update the value on Pushed screen, it would not re-render Main screen to show the updated value.
I'd recommend to use MobX if you want Context like API. You could checkout my boilerplate project https://github.com/jinshin1013/rnn-boilerplate.

Warning: Each child in a list should have a unique "key" prop.%s%s

Hello to the whole community.
I am doing a project in which the restaurants in my city can place their dishes and generate orders through the Application.
But I am having an error with my project when executing it.
This is the mistake I am having.
Warning: Each child in a list should have a unique "key" prop.%s%s
Check the render method of `VirtualizedList`., ,
in CellRenderer (at VirtualizedList.js:767)
in VirtualizedList (at FlatList.js:676)
in FlatList (at Meals.tsx:14)
in RCTView (at Meals.tsx:12)
in Meals (at SceneView.js:9)
in SceneView (at StackViewLayout.tsx:900)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at StackViewCard.tsx:106)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at screens.native.js:100)
in Screen (at StackViewCard.tsx:93)
in Card (at createPointerEventsContainer.tsx:95)
in Container (at StackViewLayout.tsx:975)
in RCTView (at screens.native.js:131)
in ScreenContainer (at StackViewLayout.tsx:384)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at StackViewLayout.tsx:374)
in PanGestureHandler (at StackViewLayout.tsx:367)
in StackViewLayout (at withOrientation.js:30)
in withOrientation (at StackView.tsx:104)
in RCTView (at Transitioner.tsx:267)
in Transitioner (at StackView.tsx:41)
in StackView (at createNavigator.js:80)
in Navigator (at createKeyboardAwareNavigator.js:12)
in KeyboardAwareNavigator (at SceneView.js:9)
in SceneView (at StackViewLayout.tsx:900)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at StackViewCard.tsx:106)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at screens.native.js:100)
in Screen (at StackViewCard.tsx:93)
in Card (at createPointerEventsContainer.tsx:95)
in Container (at StackViewLayout.tsx:975)
in RCTView (at screens.native.js:131)
in ScreenContainer (at StackViewLayout.tsx:384)
in RCTView (at createAnimatedComponent.js:151)
in AnimatedComponent (at StackViewLayout.tsx:374)
in PanGestureHandler (at StackViewLayout.tsx:367)
in StackViewLayout (at withOrientation.js:30)
in withOrientation (at StackView.tsx:104)
in RCTView (at Transitioner.tsx:267)
in Transitioner (at StackView.tsx:41)
in StackView (at createNavigator.js:80)
in Navigator (at createKeyboardAwareNavigator.js:12)
in KeyboardAwareNavigator (at createAppContainer.js:430)
in NavigationContainer (at withExpoRoot.js:26)
in RootErrorBoundary (at withExpoRoot.js:25)
in ExpoRoot (at renderApplication.js:40)
in RCTView (at AppContainer.js:101)
in DevAppContainer (at AppContainer.js:115)
in RCTView (at AppContainer.js:119)
in AppContainer (at renderApplication.js:39)
I am doing the project on my frontend with React-native.
**My code is this - my frontend **
App.js
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import MealsScreen from './src/screens/Meals';
import Modal from './src/screens/Modal';
const AppNavigation = createStackNavigator({
Meals: {
screen: MealsScreen
}
}, {
initialRouteName: 'Meals'
});
const RootStack = createStackNavigator( {
Main: AppNavigation,
Modal: Modal,
}, {
mode: 'modal',
headerMode: 'none',
});
export default createAppContainer( RootStack );
Meals
import React from 'react';
import { Text, View, StyleSheet, FlatList } from 'react-native';
import ListItem from '../components/ListItem';
import UseFetch from '../hooks/useFetch';
const Meals = ({navigation}) => {
const { loading, data: meals } = UseFetch('https://serverless.mgyavega.now.sh/api/meals');
return(
<View style = { styles.container }>
{ loading ? <Text style = { styles.text }>Cargando por favor espere...</Text> :
<FlatList
style = { styles.list }
data = { meals }
keyExtractor= { x => x.id }
renderItem = {({ item }) =>
<ListItem
onPress={ () => navigation.navigate('Modal', { id: item.id })}
name = { item.name }
/>
}
/>
}
</View>
)
}
Meals.navigationOptions = ({
title: 'Comidas Disponibles',
});
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'flex-start',
justifyContent: 'flex-start'
},
list: {
alignSelf: 'stretch'
},
text: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
});
export default Meals;
Create a list that calls the Flatlist action and manage the information on my list.
List.js
import React from 'react';
import { TouchableOpacity, Text, StyleSheet } from 'react-native';
export default ({ name, onPress }) => {
return (
<TouchableOpacity onPress = { onPress } style={ styles.container }>
<Text style = { styles.text }> {name} </Text>
</TouchableOpacity>
)
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: 15,
height: 60,
justifyContent: 'center',
borderBottomWidth: 1,
borderBottomColor: '#eee'
},
text: {
fontSize: 16
}
});
Get the url of my project.
UseFecth.js
import { useEffect, useState } from 'react';
const UseFetch = ( url ) => {
const [loading, setLoading] = useState(true);
const [ data, setData] = useState([]);
const fetchData = async () => {
const response = await fetch(url);
const data = await response.json();
setData(data);
setLoading(false);
};
useEffect(() => {
fetchData();
}, [] );
return { loading, data }
}
export default UseFetch;
My modal.js
import React from 'react';
import { View, Text, } from 'react-native';
import UseFetch from '../hooks/useFetch';
export default ({navigation}) => {
const id = navigation.getParam('_id');
const { loading, data } = UseFetch(`https://serverless.mgyavega.now.sh/api/meals/${id}`);
console.log( 'Información del id del menú: ', id );
return (
loading ? <Text>Cargando </Text> :
<View>
<Text> </Text>
<Text> </Text>
</View>
)
}
I am doing my backend with MongoDB, Ziet and Node.js.
This is my route.
index.js
var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
var meals = require('./routes/meals');
var orders = require('./routes/orders');
mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true } );
app.use('/api/meals', meals);
app.use('/api/orders', orders);
module.exports = app;
Meals.js
var express = require('express');
var Meals = require('../models/meals');
var router = express.Router();
router.get('/', ( req, res ) => {
Meals.find()
.exec()
.then( x => {
res.status(200).send(x)
});
});
router.get('/:id', ( req, res ) => {
Meals.findById(req.params.id)
.exec()
.then( x => {
res.status(200).send(x);
});
});
Models.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
const Meal = mongoose.model('Meal', new Schema({
name: String,
desc: String,
}));
module.exports = Meal;
I don't know why the information is duplicating me.
I appreciate the collaboration you can give me.
Thank you.
Mario
My best guess would be that this line is producing duplicate key's.
keyExtractor= { x => x.id }
In this line, keyExtractor= { x => x.id } the id might have been duplicated.
Eg.
[{"id":1,"name":"hello"},{"id":1,"name":"world"}]
Both the values have same ids.
Try keyExtractor= { x => x } if all the values in the list are unique
Otherwise you can use any property in a list. Eg .keyExtractor= { x => x.name }
The problem with using database ids as keys is that depending on your query, your database can return rows with duplicate ids.
I use uuid (https://www.npmjs.com/package/uuid) in my projects, it works like a charm!
if someone has the same thing, the solution is the easiest.
In keyExtractor = {x => x.id} it is changed with keyExtractor = {x => x._id} since in the mongoDB database the id of each record is _id and as I was bringing it with id that gave me It was causing duplicity.
Everything else is correct.
He hoped he would help someone.

How can I modify this code so that render waits for Promise Items?

I am new to React and I load all the data from my database initially on page load but there is info I need to find in an array and apparently it isn't instant. What do I need to do to make sure the render method only renders the objects when the object promises have resolved?
I haven't tried much... I'm really stuck here.
This seems different than the other problems I've read here because I load a bunch on info in the beginning just fine but I need to call some team information every time a function is called so it isn't as simple as loading it once because the object i need is always different.
This code is the main issue. I also included the full file below:
I did some modification to the code in a edit: I realized that I just need to call the opponent team because I have the player team already.
if (team.id === game.team_1) {
var redTeam = team;
// set blueTeam based on game.team_1
// firebase.teams().doc('teams/{game.team_2}')
} else {
var blueTeam = team;
// set redTeam based on game.team_1
// firebase.teams().doc('teams/{game.team_1}')
}
Full file:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import Async from 'react-promise'
import { withFirebase } from '../Firebase';
// import * as ROUTES from '../../constants/routes';
import { Container, Image, Spinner, Col, Row, Card, Accordion, Button } from 'react-bootstrap'
class PlayerGameList extends Component {
constructor(props) {
super(props);
this.state = {
loadingTeams: false,
loadingSchedule: false,
teams: [],
schedule: []
};
}
componentDidMount() {
this.setState({
loadingTeams: true,
loadingSchedule: true,
});
this.unsubscribe = this.props.firebase
.teams()
.where('players', 'array-contains', '-LXkkB7GNvYrU4UkUMle')
.onSnapshot(snapshot => {
let teams = [];
snapshot.forEach(doc =>
teams.push({ ...doc.data(), uid: doc.id }),
);
this.setState({
teams,
loadingTeams: false,
});
});
this.unsubscribe2 = this.props.firebase
.schedule()
.onSnapshot(snap => {
let schedule = [];
snap.forEach(doc =>
schedule.push({ ...doc.data(), uid: doc.id }),
);
this.setState({
schedule,
loadingSchedule: false,
});
});
}
componentWillUnmount() {
this.unsubscribe();
this.unsubscribe2();
}
render() {
const { teams, schedule, loadingTeams, loadingSchedule } = this.state;
return (
<div>
<h2>Games</h2>
{loadingTeams && loadingSchedule && <div colSpan="12"><Spinner animation="border" role="status">
<span className="sr-only">Loading...</span>
</Spinner></div>}
{/* CONTENT */}
<Container fluid>
<Row>
{getTeams({ teams, schedule })}
</Row>
</Container>
</div >
);
}
}
function getTeams({ teams, schedule }) {
if (!teams) {
return null;
}
if (!teams.length) {
return null;
} else {
return teams.map(team => getGames({ team, schedule }))
}
}
function getGames({ team, schedule }) {
schedule.sort((a, b) => (a.time > b.time) ? -1 : 1)
if (!schedule) {
return null;
}
if (!schedule.length) {
return null;
} else {
return schedule.map(game => guts({ team, game }));
}
}
function guts({ team, game }) {
const image = {
height: '25px',
width: '25px'
}
if (team.id === game.team_1) {
var redTeam = team;
// set blueTeam based on game.team_1
// firebase.teams().doc('teams/{game.team_2}')
} else {
var blueTeam = team;
// set redTeam based on game.team_1
// firebase.teams().doc('teams/{game.team_1}')
}
if (game.team_1 === team.id || game.team_2 === team.id) {
var time = new Date(game.time.seconds * 1000);
var dateFormat = require('dateformat');
var finalTime = dateFormat(time, 'ddd mmm dd, h:MM tt')
return (
<Col lg='4' md='6' sm='12' key={game.uid} style={{ marginBottom: '15px' }}>
<Card>
<Card.Body>
<Row>
<Image src={team.logo} style={image} roundedCircle />
<p>{team.name}</p>
<div style={{ height: '25px', width: '25px', backgroundColor: 'red' }}></div>
</Row>
<Row>
<Image src={team.logo} style={image} roundedCircle />
<p>{team.name}</p>
<div style={{ height: '25px', width: '25px', backgroundColor: 'blue' }}></div>
</Row>
<Row>
<div>
{finalTime}
</div>
</Row>
</Card.Body>
<Accordion>
<Card style={{ margin: '0', padding: '0' }}>
<Card.Header>
<Accordion.Toggle as={Button} variant="link" eventKey="0">
Show Match IDs
</Accordion.Toggle>
</Card.Header>
<Accordion.Collapse eventKey="0">
<Card.Body>{game.match_id}</Card.Body>
</Accordion.Collapse>
</Card>
</Accordion>
</Card>
</Col>
);
}
}
export default withFirebase(PlayerGameList);
The items all load blank then a few seconds later all the console logs come through with the array objects. When I tell it to await the program just throws an error.

Resources