Not all state attributes populating from firebase databse in react app - reactjs

I've been following a react tutorial by Wes Bos and I can't seem to get some of the state to persist using the firebase database. My 'order' state seems to persist, but the 'fishes' state in my inventory doesn't.
Specifically, I can see the changes made to 'fishes' once I change them in the react app, but if I exit the store and come back in, the order persists but the 'fishes' do not.
base.js
import Rebase from 're-base';
import * as firebase from 'firebase';
const app = firebase.initializeApp({
apiKey: "XXXXXXXXX",
authDomain: "XXXXXXXX",
databaseURL: "XXXXXXXXXXXXXXXXX",
projectId: "XXXXXXXXXXXX",
storageBucket: "XXXXXXXXXXXXXXXXX",
});
const base = Rebase.createClass(app.database());
export default base;
app.js
import React from 'react';
import Header from './Header';
import Order from './Order';
import Inventory from './Inventory';
import Fish from './Fish';
import sampleFishes from '../sample-fishes';
import base from '../base';
import PropTypes from 'prop-types';
import * as firebase from 'firebase';
export default class App extends React.Component {
constructor() {
super();
this.addFish = this.addFish.bind(this);
this.loadSamples = this.loadSamples.bind(this);
this.addToOrder = this.addToOrder.bind(this);
this.updateFish = this.updateFish.bind(this);
this.removeFish = this.removeFish.bind(this);
this.removeFromOrder = this.removeFromOrder.bind(this);
this.state = {
fishes: {},
order: {},
};
}
componentDidMount() {
this.FishRef = base.syncState(`${this.props.match.params.storeId}/fishes`,
{
context: this,
state: 'fishes'
});
}
componentDidMount() {
this.OrderRef = base.syncState(`${this.props.match.params.storeId}/order`,
{
context: this,
state: 'order'
});
}
componentWillUnmount() {
base.removeBinding(this.FishRef);
base.removeBinding(this.OrderRef);
}
addFish(fish) {
const fishes = {...this.state.fishes};
const timestamp = Date.now();
fishes[`fish-${timestamp}`] = fish;
this.setState({ fishes });
}
removeFish(key) {
const fishes = {...this.state.fishes};
fishes[key] = null;
this.setState({ fishes });
}
updateFish(key, updatedFish) {
const fishes = {...this.state.fishes};
fishes[key] = updatedFish;
this.setState({ fishes });
}
loadSamples() {
this.setState({
fishes: sampleFishes
});
}
addToOrder(key) {
const order = {...this.state.order};
order[key] = order[key] + 1 || 1;
this.setState({ order });
}
removeFromOrder(key){
const order = {...this.state.order};
delete order[key];
this.setState({ order });
}
render() {
return(
<div className="catch-of-the-day">
<div className="menu">
<Header tagline="Fresh seafood market"/>
<ul className="list-of-fishes">
{Object
.keys(this.state.fishes)
.map(key => <Fish key={key}
details={this.state.fishes[key]}
addToOrder={this.addToOrder}
index={key}
/>)
}
</ul>
</div>
<Order fishes={this.state.fishes}
order={this.state.order}
removeFromOrder={this.removeFromOrder}/>
<Inventory addFish={this.addFish}
loadSamples={this.loadSamples}
fishes = {this.state.fishes}
updateFish = {this.updateFish}
removeFish = {this.removeFish}/>
</div>
);
}
}
App.propTypes = {
match: PropTypes.object.isRequired
}

you declared componentDidMount twice , here :
componentDidMount() {
this.FishRef = base.syncState(`${this.props.match.params.storeId}/fishes`,
{
context: this,
state: 'fishes'
});
}
componentDidMount() {
this.OrderRef = base.syncState(`${this.props.match.params.storeId}/order`,
{
context: this,
state: 'order'
});
}
this mean the first will execute and the second will not or the other way around .
fix this by add the body of second the body of the first like this :
componentDidMount() {
this.FishRef = base.syncState(`${this.props.match.params.storeId}/fishes`,
{
context: this,
state: 'fishes'
});
this.OrderRef = base.syncState(`${this.props.match.params.storeId}/order`,
{
context: this,
state: 'order'
});
}

Related

ReactJS -- Unable to find latest title from an api causing error

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

Reactjs and Superagent pt3

I'm making progress on this app. I'm able to access and render the list of ingredients now I need to do the same with the name of the recipe. Postman indicates that it is under recipes.body.matches[0].sourceDisplayName. I created another function, similar to what got me the ingredients. Getting the following error...
TypeError: Cannot read property 'map' of undefined
import React from 'react';
import Request from 'superagent';
import _ from 'lodash';
export class Yum extends React.Component {
constructor(){
super();
this.state = {
searchQuery: 'onion',
recipe: {
ingredients: []
}
};
this.search = this.search.bind(this);
this.queryUpdate = this.queryUpdate.bind(this);
}
componentWillMount(){
this.search(this.state.searchQuery);
}
render(){
//const title = 'Onion Soup'; // Get this from somwhere else ?
const {recipe, searchQuery} = this.state; // Get state properties
const displayName = _.get(recipe, 'sourceDisplayName').map((sourceDisplayName) => {
return (<h4>{displayName}</h4>)
});
const listItems = _.get(recipe, 'ingredients', []).map((ingredient, sourceDisplayName) => {
return (<h5>{ingredient}</h5>);
});
return(
<div>
<input onChange={this.queryUpdate} type="text" value={searchQuery} />
<h4>{displayName}</h4>
<ul>
<li>{listItems}</li>
</ul>
</div>
)
}
queryUpdate(event) {
const searchQuery = event.target.value; // Get new value from DOM event
this.setState({searchQuery}); // Save to state
this.search(searchQuery); // Search
}
search(searchQuery) {
const url = `http://api.yummly.com/v1/api/recipes?_app_id=5129dd16&_app_key=9772f1db10ba433223ad4e765dc2b537&q=${searchQuery}&maxResult=1`
Request.get(url).then((response) => {
this.setState({
recipe: response.body.matches[0]
});
});
}
}
export default Yum;
Any suggestions?

How to send automatic constant message in web app based on reactjs?

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;

error display data from firebase to react bootstrap table

I want to display data from my firebase database to react bootstrap table. But, I can't show live data if after refresh.
This is my react component code
import React, { Component } from 'react';
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
import PageHeader from 'react-bootstrap/lib/PageHeader';
import database from './database';
const ref = database.ref('users');
ref.on('value', gotData, errData);
const products = [];
function gotData(data) {
const userdata = data.val();
const keys = Object.keys(userdata);
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
products.push({
name: userdata[k].nama, address: userdata[k].address, email: userdata[k].email
});
}
}
function errData(err) {
console.log(err);
}
class Member extends Component {
constructor(props) {
super(props);
this.state = {
text:''
};
}
handleClick = (rowKey) => {
alert(this.refs.table.getPageByRowKey(rowKey));
}
render(){
return (
<div>
<div className="col-lg-12">
<PageHeader>Members</PageHeader>
</div>
<BootstrapTable
ref='table'
data={ products }
pagination={ true }
search={ true }>
<TableHeaderColumn dataField='name' isKey={true} dataSort={true}>Name</TableHeaderColumn>
<TableHeaderColumn dataField='address' dataSort={true}>Address</TableHeaderColumn>
<TableHeaderColumn dataField='email'>Email</TableHeaderColumn>
</BootstrapTable>
</div>
);
}
}
export default Member;
and this is my initialize database code
import firebase from 'firebase';
const config = {
apiKey: '......',
authDomain: '......',
databaseURL: '....',
projectId: '....',
storageBucket: '....',
messagingSenderId: '....'
};
firebase.initializeApp(config);
const database = firebase.database();
export default database;
Help me in this, Thanks.
You have to tell the component to re-render, when there is a change in data. I don't think the functions related to firebase should live outside the component. Instead they should live within the component. You should do something like below. Hope it helps
import React, { Component } from 'react';
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
import PageHeader from 'react-bootstrap/lib/PageHeader';
import database from './database';
class Member extends Component {
constructor(props) {
super(props);
this.state = {
text:'',
products: []
};
this.userRef = database.ref('users');
}
componentDidMount() {
this.userRef.on('value', this.gotData, this.errData);
}
gotData = (data) => {
let newProducts = []
const userdata = data.val();
const keys = Object.keys(userdata);
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
newProducts.push({
name: userdata[k].nama, address: userdata[k].address, email: userdata[k].email
});
}
this.setState({products: newProducts});
}
errData = (err) => {
console.log(err);
}
handleClick = (rowKey) => {
alert(this.refs.table.getPageByRowKey(rowKey));
}
render(){
return (
<div>
<div className="col-lg-12">
<PageHeader>Members</PageHeader>
</div>
<BootstrapTable
ref='table'
data={ this.state.products }
pagination={ true }
search={ true }>
<TableHeaderColumn dataField='name' isKey={true} dataSort={true}>Name</TableHeaderColumn>
<TableHeaderColumn dataField='address' dataSort={true}>Address</TableHeaderColumn>
<TableHeaderColumn dataField='email'>Email</TableHeaderColumn>
</BootstrapTable>
</div>
);
}
}
export default Member;
All subscription related code goes into componentDidMount and you have to unsubscribe when the component will unmount.

how can i create .env file in firebase for a react chat web app?

import React, { Component } from 'react';
import MessagePane from './MessagePane';
import ChannelList from './ChannelList';
import { getMessages, getChannels, saveMessage, onNewMessage } from './storage';
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);
}
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;
i do not know how to make constant in .env file for firebase. please help me if anyone know about this and how to connect and access firebase database for real time reload. i have also change the rules but it does not work for me.

Resources