I have a Landing component and a NewsLatest component. I am hitting on an api and trying to find the article with the latest timestamp but iam unable to get it done in reactJS.I checked the js code its working fine but in react it is not rendering. Kindly suggest something.
import React, { Component } from 'react'
import NewsSearch from '../NewsSearch/NewsSearch';
import NewsLatest from '../NewsLatest/NewsLatest';
import './Landing.css';
import axios from 'axios';
class Landing extends Component {
state={
newsList: []
}
componentDidMount(){
axios.get(`https://api.nytimes.com/svc/topstories/v2/home.json?api-key=7cK9FpOnC3zgoboP2CPGR3FcznEaYCJv`)
.then(res=> {
this.setState({newsList: res.data.results});
});
}
render() {
// console.log(this.state.newsList);
return (
<div className="landing text-center text-white">
<h1>News Portal</h1>
<div className="news-search">
<NewsSearch />
</div>
<div className="news-latest">
<NewsLatest newsList={this.state.newsList}/>
</div>
</div>
)
}
}
export default Landing;
import React, { Component } from 'react';
// import PropTypes from 'prop-types';
class NewsLatest extends Component {
constructor(props){
super(props);
this.state = {
newsTitle:'',
abstract:'',
newsUrl:'',
}
// this.newsLatest = this.newsLatest.bind(this);
}
newsLatest = (e)=>{
// e.preventDefault();
const {newsList} = this.props;
let maxTime = newsList.map(function(o) {
return new Date(o.updated_date);
});
let maximumValue = Math.max(...maxTime);
let latestnews = newsList.filter(function (el) {
return maximumValue === new Date(el.updated_date).getTime();
})[0];
if(latestnews){
this.setState({newsTitle: latestnews.title});
return (<h4>{this.state.newsTitle}</h4>);
}
}
newsTitle = () => (
this.props.newsList.map(item => (<h2 key={item.title}>{item.title}</h2>))
)
render() {
console.log(this.props.newsList);
return (
<div>
<h2>News Latest....</h2>
{this.newsLatest()}
</div>
);
}
}
export default NewsLatest;
There is some issue in rendering in NewsLatest component. KIndly suggest something.
Try this:
You must probably be getting a maximum depth error, use a lifecycle method instead like componentDidUpdate. Update your component state only if the previous props are different from the newer ones.
Read more here: https://reactjs.org/docs/react-component.html
import React, { Component } from "react";
// import PropTypes from 'prop-types';
class NewsLatest extends Component {
constructor(props) {
super(props);
this.state = {
newsTitle: "",
abstract: "",
newsUrl: ""
};
// this.newsLatest = this.newsLatest.bind(this);
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.newsList !== this.props.newsList) {
const { newsList } = this.props;
let maxTime = newsList.map(function(o) {
return new Date(o.updated_date);
});
let maximumValue = Math.max(...maxTime);
let latestnews = newsList.filter(function(el) {
return maximumValue === new Date(el.updated_date).getTime();
})[0];
this.setState({ newsTitle: latestnews.title });
}
}
// newsLatest = e => {
// // e.preventDefault();
// const { newsList } = this.props;
// let maxTime = newsList.map(function(o) {
// return new Date(o.updated_date);
// });
// let maximumValue = Math.max(...maxTime);
// let latestnews = newsList.filter(function(el) {
// return maximumValue === new Date(el.updated_date).getTime();
// })[0];
// console.log(latestnews)
// if (latestnews && latestnews.hasOwnProperty('length') && latestnews.length>0) {
// return <h4>{this.state.newsTitle}</h4>;
// }
// };
newsTitle = () =>
this.props.newsList.map(item => <h2 key={item.title}>{item.title}</h2>);
render() {
console.log(this.props.newsList);
return (
<div>
<h2>News Latest....</h2>
<h4>{this.state.newsTitle}</h4>
</div>
);
}
}
export default NewsLatest;
Also, a sandbox: https://codesandbox.io/s/hungry-frog-z37y0?fontsize=14
Related
I am trying to fetch the firebase data into a array and for each element create a button with that element as an id and name.
import React, { Component } from 'react'
import app from './firebase'
import firebase from "firebase/app";
import "firebase/database"
import { BsFillSquareFill } from "react-icons/bs";
import { Container,Row, Col } from "react-bootstrap";
import { withRouter } from 'react-router-dom';
var chambers = []
export default class ChamberClass extends Component {
constructor(props) {
super(props);
}
getButtonsUsingMap = () => {
return chambers.map((number) => {
return <button id={number} onClick={this.routeChange} className="btn"><BsFillSquareFill key = {number} color='green' className="icon "/>
<center>{number}</center>
</button>
})
}
componentDidMount(){
var chamberListen = firebase.database().ref()
chamberListen.on('value', snapshot => {
snapshot.forEach((cham) => {
var chamKey = cham.key;
var chamData = cham.val();
chambers.push(chamKey)
// document.getElementById("Chambers").innerHTML = chambers
console.log(chambers)
})
})
}
render() {
return (
<div>
<h4 className='RoomsTitle'>Rooms</h4>
<hr></hr>
{this.getButtonsUsingMap()}
</div>
)
}
}
I do get the console log which probably means that the firebase data is being accessed properly. However no buttons are being created.
Also when i move the code block inside componentDidMount() to the top of the ChamberClass, the buttons do get displayed but only once. After every successive attempt after reload or manually going to the route doesnt help either.
You need to put the array chambers into the component state. Without that you change the value but your component doesn't know that something changed and wont render as you expect it. By putting it into the component state it will know when it changes:
import React, { Component } from "react";
import app from "./firebase";
import firebase from "firebase/app";
import "firebase/database";
import { BsFillSquareFill } from "react-icons/bs";
import { Container, Row, Col } from "react-bootstrap";
import { withRouter } from "react-router-dom";
export default class ChamberClass extends Component {
state = {
chambers: [],
};
constructor(props) {
super(props);
}
getButtonsUsingMap = () => {
return this.state.chambers.map((number) => {
return (
<button id={number} onClick={this.routeChange} className="btn">
<BsFillSquareFill key={number} color="green" className="icon " />
<center>{number}</center>
</button>
);
});
};
componentDidMount() {
var chamberListen = firebase.database().ref();
chamberListen.on("value", (snapshot) => {
var chambers = [];
snapshot.forEach((cham) => {
var chamKey = cham.key;
var chamData = cham.val();
chambers.push(chamKey);
// document.getElementById("Chambers").innerHTML = chambers
console.log(chambers);
});
this.setState({ chambers });
});
}
render() {
return (
<div>
<h4 className="RoomsTitle">Rooms</h4>
<hr></hr>
{this.getButtonsUsingMap()}
</div>
);
}
}
i have made a twillio video app.i can show local video on Laptop website but when i join from another chrome tab or mobile phone chrome browser the video on laptop goes black and only one video is showing whereas both videos should show properly.i am following this tutorial
https://www.twilio.com/blog/build-a-custom-video-chat-app-with-react-and-twilio-programmable-video
here is my code
App.js
import './App.scss';
import React, {Component} from 'react';
import Room from './Components/Room';
const { connect } = require('twilio-video');
const Token = {"identity":"Jose Corkery","token":"...sioAMt4..."}
class App extends Component {
constructor(props) {
super(props)
this.state = {
identity: '',
room: null
}
this.inputRef = React.createRef();
this.joinRoom = this.joinRoom.bind(this);
this.returnToLobby = this.returnToLobby.bind(this);
this.updateIdentity = this.updateIdentity.bind(this);
this.removePlaceholderText = this.removePlaceholderText.bind(this)
}
async joinRoom() {
try {
// const response = Token
// const data = await response.json();
const room = await connect(Token.token, {
name: 'cool-room',
audio: true,
video: true
});
// alert(room)
this.setState({ room: room });
} catch(err) {
alert(err);
}
}
updateIdentity(event) {
this.setState({
identity: event.target.value
});
}
returnToLobby() {
this.setState({ room: null });
}
removePlaceholderText() {
this.inputRef.current.placeholder = '';
}
render() {
const disabled = this.state.identity === '' ? true : false;
return (
<div className="app">
{
this.state.room === null
? <div className="lobby">
<input
ref={this.inputRef}
onClick={this.removePlaceholderText}
placeholder="What's your name?"
onChange={this.updateIdentity}
/>
<button disabled = {disabled} onClick={this.joinRoom}>Join Room</button>
</div>
: <Room returnToLobby={this.returnToLobby} room={this.state.room} />
}
</div>
);
}
}
export default App;
Room.jsx
import React, { Component } from 'react';
import Participant from './Participant';
const { connect } = require('twilio-video');
class Room extends Component {
componentDidMount() {
this.props.room.on('participantConnected', participant => this.addParticipant(participant));
this.props.room.on('participantDisconnected', participant => this.removeParticipant(participant));
window.addEventListener("beforeunload", this.leaveRoom);
}
componentWillUnmount() {
this.leaveRoom();
}
addParticipant(participant) {
console.log(`${participant.identity} has joined the room.`);
alert(`+ Participant : ${participant.identity}`)
this.setState({
remoteParticipants: [...this.state.remoteParticipants, participant]
})
}
removeParticipant(participant) {
alert(`Leaving : ${participant.identity}`)
console.log(`${participant.identity} has left the room`);
this.setState({
remoteParticipants: this.state.remoteParticipants.filter(p => p.identity !== participant.identity)
});
}
leaveRoom() {
this.props.room.disconnect();
this.props.returnToLobby();
}
constructor(props) {
super(props)
this.state = {
remoteParticipants: Array.from(this.props.room.participants.values())
}
this.leaveRoom = this.leaveRoom.bind(this);
}
render() {
return (
<div className="room">
<div className="participants">
<Participant
key={this.props.room.localParticipant.identity}
localParticipant="true"
participant={this.props.room.localParticipant} />
{
this.state.remoteParticipants.map(participant =>
<Participant key={participant.identity} participant={participant} />
)
}
</div>
<button id="leaveRoom" onClick={this.leaveRoom}>Leave Room</button>
</div>
);
}
}
export default Room
Participant.jsx
import React, { Component } from 'react';
import Track from './Track';
const { connect } = require('twilio-video');
class Participant extends Component {
componentDidMount() {
if (!this.props.localParticipant) {
this.props.participant.on('trackSubscribed', track => this.addTrack(track));
}
}
constructor(props) {
super(props);
const existingPublications = Array.from(this.props.participant.tracks.values());
const existingTracks = existingPublications.map(publication => publication.track);
const nonNullTracks = existingTracks.filter(track => track !== null)
this.state = {
tracks: nonNullTracks
}
}
addTrack(track) {
this.setState({
tracks: [...this.state.tracks, track]
});
}
render() {
return (
<div className="participant" id={this.props.participant.identity}>
<div className="identity">{this.props.participant.identity}</div>
{
this.state.tracks.map(track =>
<Track key={track} filter={this.state.filter} track={track}/>)
}
</div>
);
}
}
export default Participant
Track.jsx
import React, { Component } from 'react';
class Track extends Component {
componentDidMount() {
if (this.props.track !== null) {
const child = this.props.track.attach();
this.ref.current.classList.add(this.props.track.kind);
this.ref.current.appendChild(child)
}
}
constructor(props) {
super(props)
this.ref = React.createRef();
}
render() {
return (
<div className="track" ref={this.ref}>
</div>
)
}
}
export default Track
demo:https://android-anime.web.app
i have only two video events onJoin and onLeave do i need additional events ?
what is the solution? if your solution works i will award you best answer.Thanks !!
import { Mongo } from 'meteor/mongo';
import { Meteor } from 'meteor/meteor';
import React, {Component} from 'react';
import {check} from 'meteor/check';
export const Adressen = new Mongo.Collection('Phonebook');
if (Meteor.isServer) {
Meteor.publish('ArrayToExport', function(branches) {
check(branches, [Match.Any]);
if(branches.length > 10){
return this.ready()
};
return Adressen.find(
{branche: {$in: branches}}, {fields: {firmenname:1, plz:1}}
);
});
}
.
import React, { Component } from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import {Adressen} from "../api/MongoDB";
class ExportArray extends Component{
constructor(props){
super(props);
this.state = {
branches: this.props.filteredBranches
};
}
render(){
return(
<div>
<button onClick={this.exportArrays}></button>+
</div>
);
}
}
export default withTracker( (branches) => {
Meteor.subscribe('ArrayToExport', branches);
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
this.props.filteredBranche is a pure array,generated through controlled input field. this.props.filteredBranches changes as Input changes, in parent Component.
I thought I was sending my this.props.filteredBranches as an argument through withTracker function. But nothing is passed to the publish function.
if (Meteor.isServer) {
arrayExfct = function (array){
return {
find: {branche:{$in: array }},
fields: {firmenname:1, plz:1}
};
}
Meteor.publish('ArrayToExport', function (array) {
return Adressen.find(
arrayExfct(array).find, arrayExfct(array).fields);
});
}
.
export default withTracker( () => {
arrayExfct = function(array) {
return {
find: {branche: {$in: array}},
fields: {firmenname:1, plz:1}
}
}
var array = ['10555'];
Meteor.subscribe('ArrayToExport', array );
var arrayExfct = Adressen.find(arrayExfct(array).find, arrayExfct(array).fields);
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
It would help if you also added an example of where you used this component and how you pass props to it, but I think I see your problem.
You expect the local state in your rendering component to get into the withTracker container, but that would be the other way around. When you make the withTracker container, you are really making another react component that renders your display component (ExportArray) and passes the data (ArrayToExport) down into it.
So, props go like this currently:
external render -> withTracker component -> ExportArray
What you need to do it to get the filteredBranches (which you pass from a parent component?) from the props argument in withTracker and pass that to the subscribtion,
class ExportArray extends Component{
exportArrays () {
const { ArrayToExport } = this.props;
}
render(){
const { ArrayToExport } = this.props;
return(
<div>
<button onClick={this.exportArrays}></button>+
</div>
);
}
}
export default withTracker(propsFromParent => {
const { filteredBranches } = propsFromParent;
Meteor.subscribe('ArrayToExport', filteredBranches);
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
Hi the issue is with the code below. The parameter called branches is the props so branches.branches is the array you passed in.
export default withTracker( (branches) => {
Meteor.subscribe('ArrayToExport', branches);
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
Try the following.
export default withTracker( ({branches}) => {
Meteor.subscribe('ArrayToExport', branches);
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
Notice all that changed was
(branches)
became
({branches})
I solved my problem with a combination of Session Variables and State.
//Client
import React, { Component } from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import {Adressen} from "../api/MongoDB";
import {Meteor} from 'meteor/meteor';
import { Session } from 'meteor/session';
class ExportArray extends Component{
constructor(){
super();
this.state = {
x: [],
y: []
};
this.exportArrays = this.exportArrays.bind(this);
}
exportArrays(e){
e.preventDefault();
this.setState({x: this.props.filteredBranches});
this.setState({y: this.props.filteredPostleitzahlen});
}
render(){
var selector = {branche: {$in: this.state.x},plz: {$in: this.state.y}};
Session.set('selector', selector);
return(
<div>
<button onClick={this.exportArrays}> Commit </button>
</div>
);
}
}
export default withTracker( () => {
const ArrayfürExport = Meteor.subscribe('ArrayToExport', Session.get('selector') );
return {
ArrayToExport: Adressen.find({}).fetch()
};
})(ExportArray);
//Server
Meteor.publish('ArrayToExport', function (selector) {
console.log('von mongodb', selector);
return Adressen.find(
selector
, {
fields: {firmenname:1, plz:1}
});
});
}
I'm importing a child component and rendering it in my app.js file. The component has a console.log for debugging but it keeps running the log, seemingly without end. Worried something might be wrong, new to ReactJS and wondering if this is a common issue and how to resolve it.
App.js:
import React, { Component } from 'react';
import {BrowserRouter as Router, Link} from 'react-router-dom';
import './App.css';
import axios from 'axios'
import Header from './components/header';
import Page from './components/page';
class App extends Component {
constructor(props) {
super(props);
this.state = {
title: 'John Doe',
nav: {},
currentPage: "",
pageContent: "",
pageTitle: "",
pageTemplate: "",
pageId: 0,
pageCustomMeta: {},
archiveData: []
}
}
getMainMenu(){
axios.get('http://admin.sitedata.co/menus/5')
.then((response) => {
this.setState({nav:response.data});
})
.catch((error) => {
console.log(error);
});
}
isHome(){
//console.log(document.location.pathname);
if(document.location.pathname === "/") {
document.body.classList.add('home');
} else {
document.body.classList.remove('home');
}
}
componentDidMount(){
/*
* get current page content
* get the main menu
* allow pageChange function to be ran
* allow isHome to be ran
*/
var slug = "";
if(document.location.pathname === "/") {
slug = "home";
} else {
slug = document.location.pathname.substr(1);
}
this.getPageData(slug);
this.getMainMenu();
this.pageChange = this.pageChange.bind(this);
this.isHome = this.isHome.bind(this);
this.triggerMenu = this.triggerMenu.bind(this);
this.triggerHire = this.triggerHire.bind(this);
this.navigate = this.navigate.bind(this);
this.setArchiveData = this.setArchiveData.bind(this);
this.resetArchiveData = this.resetArchiveData.bind(this);
this.madeChange = this.madeChange.bind(this);
//document.getElementById('loadingOverlay').classList.add('remove');
}
getPageData(slug){
console.log(this.state);
axios.get('http://admin.sitedata.co/pages?slug='+slug)
.then((response) => {
console.log(response.data);
this.setState({
pageContent:response.data[0].content.rendered,
currentPage:slug,
pageTitle:response.data[0].title.rendered,
pageTemplate:response.data[0].template,
pageId:response.data[0].id,
pageCustomMeta:response.data[0].post_meta,
archiveData:[]
},function(){
console.log(this.state);
/*
* set the page title
* check if the page is at home
* get page custom meta
*/
document.title = this.state.pageTitle;
this.isHome();
});
})
.catch((error) => {
console.log(error);
});
}
pageChange(e){
var slug = e.target.getAttribute('data-link');
var classes = e.target.classList.contains('trigger-hire');
if(classes){
this.triggerHire();
e.preventDefault();
} else {
this.getPageData(slug);
}
}
setArchiveData(archives) {
this.setState({archiveData:archives});
}
resetArchiveData() {
}
navigate (event) {
event.preventDefault()
console.log(event.target.tagName);
if (event.target.tagName === 'A') {
this.props.router.push(event.target.getAttribute('href'));
console.log('boom');
}
event.preventDefault();
}
triggerMenu(e){
var menuOverlay = document.getElementById('menuOverlay');
if(menuOverlay.classList.contains('active')){
menuOverlay.classList.remove('active');
} else {
menuOverlay.classList.add('active');
}
}
triggerHire(e){
var hireOverlay = document.getElementById('hireOverlay');
if(hireOverlay.classList.contains('active')){
hireOverlay.classList.remove('active');
} else {
hireOverlay.classList.add('active');
}
e.stopPropagation();
e.preventDefault();
}
madeChange(){
alert('changed');
}
render() {
return (
<div className="App">
<Header nav={this.state.nav} pageChange={this.pageChange} triggerMenu={this.triggerMenu} triggerHire={this.triggerHire}/>
<Page madeChange={this.madeChange}
currentPage={this.state.currentPage}
nav={this.state.nav}
pageChange={this.pageChange}
isHome={this.isHome}
pageContent={this.state.pageContent}
pageTitle={this.state.pageTitle}
pageTemplate={this.state.pageTemplate}
pageId={this.state.pageId}
pageCustomMeta={this.state.pageCustomMeta}
archiveData={this.state.archiveData}
triggerHire={this.triggerHire}
navigate={this.navigate}
setArchiveData={this.setArchiveData}
/>
</div>
);
}
}
export default App;
Page.js
import React, { Component } from 'react';
import {BrowserRouter as Router, Link} from 'react-router-dom';
import axios from 'axios'
class Page extends Component {
render() {
if(this.props.currentPage){
var currentPage = this.props.currentPage;
var pageChange = this.props.pageChange;
var customMeta = this.props.pageCustomMeta;
var pageTempalate = this.props.pageTemplate.substr(0,this.props.pageTemplate.length-4);
var pageTitle = this.props.pageTitle;
var newTitle = <h1><span><i>{pageTitle}</i></span></h1>;
var isArchive = "";
var archiveName = "";
var firstSpace = pageTitle.indexOf(' ');
if(firstSpace > -1){
var firstWord = pageTitle.substr(0, firstSpace);
var titleLast = pageTitle.substr(firstSpace);
newTitle = <h1><span><i>{firstWord}</i>{titleLast}</span></h1>
}
if(currentPage === "home"){
if(this.props.nav.items){
var navData = this.props.nav;
var navHomeItems = navData.items.map(function(navItem){
return <li key={navItem.id}><Link to={'/'+navItem.object_slug} className={navItem.classes} onClick={pageChange} data-link={navItem.object_slug}>{navItem.title}</Link></li>;
});
}
}
document.title = this.props.pageTitle;
var isArchive = customMeta.isArchive;
var archiveName = customMeta.archiveName
var worksArchive = "";
if(customMeta.isArchive && customMeta.isArchive == "true"){
if(customMeta.archiveName) {
axios.get('http://admin.sitedata.co/'+customMeta.archiveName)
.then((response) => {
var archivePages = response.data;
console.log(archivePages);
if(archiveName == "works"){
worksArchive = archivePages.map(function(work){
//console.log(worksArchive);
return <Link key={work.id} className="work-item" to="/" ><img src={work.post_meta.targetimg} /></Link>;
});
this.props.setArchiveData(worksArchive);
}
})
.catch((error) => {
console.log(error);
});
}
}
if(customMeta.pageColor){
document.body.classList.add(customMeta.pageColor);
}
if(customMeta.bgimg){
document.body.setAttribute('style', "background-image:url('"+customMeta.bgimg+"');");
}
}
return (
<Router onEnter={this.props.madeChange}>
<div className="container">
<div className={(pageTempalate !== "") ? pageTempalate : ''}>
{newTitle}
<div dangerouslySetInnerHTML={{__html:this.props.pageContent}}></div>
{this.props.archiveData}
</div>
</div>
</Router>
);
}
}
export default Page;
Distilling your code down to the essential, it looks like this:
class Page extends Component {
render() {
axios.get(url).then(response=> {
this.setState({archiveData: response.data})
})
return (
<div className="container">
{this.state.archiveData}
</div>
)
}
}
(You are doing it differently with a callback that causes the parents to send new props, but the effect is the same).
You should be able to see problem now: the render method causes a delayed change to state (or props) which in react triggers a new render. So you now have an infinite loop, just delayed by the time taken for an ajax request.
To fix this, you need to remove the ajax request from the render method. In your case, it should probably be in the parent App component.
This is my App.js and i have set my database in firebase. All the messages which i enter all display in database also.But i need to automatically send message back to me . so any one knows how to do that please help. Thank you.
import React, { Component } from 'react';
import MessagePane from './MessagePane';
import ChannelList from './ChannelList';
import { getMessages, getChannels, saveMessage, onNewMessage } from './remote_storage1';
import './App.css';
class App extends Component {
constructor() {
super();
this.state = {
messages: [],
channels: [],
selected_channel_id: null
};
this.onSendMessage = this.onSendMessage.bind(this);
this.onChannelSelect = this.onChannelSelect.bind(this);
this.filteredMessages = this.filteredMessages.bind(this);
}
componentDidMount() {
getMessages().then(messages => this.setState({messages}));
getChannels().then(channels => this.setState({channels, selected_channel_id: channels[0].id}));
onNewMessage(new_message => {
const messages = [...this.state.messages, new_message];
this.setState({messages});
});
}
onSendMessage(author, text) {
const new_message = {
id: this.state.messages[this.state.messages.length - 1].id + 1,
author,
text,
channel_id: this.state.selected_channel_id
};
saveMessage(new_message);
const messages = [...this.state.messages, new_message];
this.setState({messages});
}
onChannelSelect(id) {
this.setState({ selected_channel_id: id });
}
filteredMessages() {
return this.state.messages.filter(({channel_id}) => channel_id === this.state.selected_channel_id);
}
render() {
return (
<div className="App">
<ChannelList
channels={this.state.channels}
selectedChannelId={this.state.selected_channel_id}
onSelect={this.onChannelSelect}
/>
<MessagePane messages={this.filteredMessages()} onSendMessage={this.onSendMessage} />
</div>
);
}
}
export default App;