Error in reading and viewing Firebase data from React-JS - javascript

I just need to view my stored data in firebase on the HTML content using ReactJs. But I got lots of error while running it. The main issue I think is data not set to the this.state with this.setState command. Here is my code.
import React, {Component} from 'react';
import {database} from "../firebase/firebase";
class MempoolTable extends Component {
constructor() {
super();
this.state = {
items:null
};
}
componentDidMount(){
let reportRef = database.ref("mempool");
let newState = [];
reportRef.once("value").then((snapshot) => {
snapshot.forEach((childSnapshot) => {
let items = childSnapshot.val();
newState.push({
time: items.time,
hash: items.hash,
size: items.size,
weight: items.weight
});
});
this.setState({ items: newState })
});
console.log(this.state);
}
render() {
return(
<div className="row" style={{marginTop: "30px"}}>
<h4 style={{textAlign: "center", color: "#4D4F4E"}}><b>Memory Pool</b></h4>
<h6 style={{textAlign: "center", color: "#4D4F4E"}}>(no of txs: 14, size: 168.81 kB)</h6>
<div className="col-xl-9 mx-auto" style={{marginTop: "10px"}}>
<table id="memPool" className="table table-bordered">
<thead>
<tr className="table-striped">
<th>AGE [H:M:S]</th>
<th>TRANSACTION HASH</th>
<th>FEE</th>
<th>TX SIZE[KB]</th>
</tr>
</thead>
<tbody>
{this.state.items.map(item => {
return (
<tr>
<td>{item.time}</td>
<td>{item.hash}</td>
<td>{item.size}</td>
<td>{item.weight}</td>
</tr>
)
})}
</tbody>
</table>
</div>
</div>
);
}
}
export default MempoolTable;
This is the error I got. Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method. And sometimes it shows me error like this. TypeError: Cannot read property 'map' of null
I just need to get all the data from firebase and load those data into the state. Then load those data on render part. Can someone help me to fix this issue?

Your initializing the state with null:
this.state = {
items:null
};
and callback from accessing database is asynchronous, so the render method will be called before the callback and will throw the error :
TypeError: Cannot read property 'map' of null
Given the error on the render method component wont mount, and this.setState from callback is being invoked on an unmounted component.
Possivel workarounds
Instantiate items to an empty array :
this.state = {
items:[]
};
Or prevent map for being executed on a null object:
{this.state.items ? this.state.items.map(item => {
return (
<tr>
<td>{item.time}</td>
<td>{item.hash}</td>
<td>{item.size}</td>
<td>{item.weight}</td>
</tr>
)
})
: ''}

Related

How to prevent onInput from firing during dynamic component initialization?

I have a table that has been created dynamically, and am attempting to put full CRUD capabilities onto it. For business reasons I am unable to use external libraries for this, and so have resulted in using basic HTML with react. I am currently trying to detect changes within the data. My problem is in regards to the onInput event with the div inside the tag. When the components are first initialized with the data, the onInput event fires for each one rather than waiting for an actual user input. To a degree I understand why this is happening, but I am in need of a workaround for it or an alternative. I have created a small demo below to show a mock of the current code:
Parent class:
import React, {Component} from 'react';
class FormContainer extends Component{
constructor(props){
super(props)
this.state={
rowData : myData
}
this.onInput = this.onInput.bind(this)
}
onInput = (rowKey) => {
console.log(rowKey)
}
render() {
return(
<Grid
data={this.state.rowData}
onInput={this.onInput}
/>
)
}
}
Grid class:
import React, {Component} from 'react';
class Grid extends Component{
constructor(props){
super(props)
}
render(){
let columns = [];
let rows = [];
if(this.props.data != null){
columns = this.props.data.slice(0, 1).map((row, i) => {
return(
Object.keys(row).map((column, key) => {
return(
<th key={key}>{column}</th>
)
})
)
})
rows = this.props.data.map((row, rowKey) => {
return(
<tr key={rowKey}>
{Object.keys(row).map((data, cellKey) => {
return(
<td key={cellKey} suppressContentEditableWarning="true" contentEditable="true" onChange={this.props.onInput(rowKey)}>{row[data]}</td>
)
})}
</tr>
)
})
}
return(
<table>
<thead><tr>{columns}</tr></thead>
<tbody>{rows}</tbody>
</table>
)
}
}
export default Grid;
The issue is that when your component is rendered any time, you are calling your onInputmethod:
<td
key={cellKey}
suppressContentEditableWarning="true"
contentEditable="true"
--> onChange={this.props.onInput(rowKey)}>{row[data]}</td>
Instead of calling it you have to pass the a function, in this case you can pass an anonymous function or an arrow function:
<td
key={cellKey}
suppressContentEditableWarning="true"
contentEditable="true"
--> onChange={ () => { this.props.onInput(rowKey); } }>{row[data]}</td>

Getting a Objects are not valid as a React child error even though I am not trying to render an object

As the title states, I am making an api request, and then returning a component with the contents of the api request as the prop. However, idk why I keep getting this error.
App.js
showPicture = async () =>{
//console.log(KEY)
const response = await picOfTheDay.get('',{
params: {
date:this.date,
hd: true,
api_key: 'KEY'
}
});
//console.log()
this.setState({picDayFullDescription: response}, ()=>{
return <PictureOfTheDay date = {this.state.date} picture= {this.state.picDayFullDescription.url} description={this.state.picDayFullDescription.explanation} />
})
}
render(){
return(
<div>
{/* <PictureOfTheDay date = {this.state.date} picture= {this.state.picDayFullDescription.url} description={this.state.picDayFullDescription.explanation}/> */}
{this.showPicture()}
</div>
)
}
PictureOfTheDay.js
class PictureOfTheDay extends React.Component{
constructor(props){
super(props);
}
render(){
return(
<div>
Hello?
</div>
)
}
}
Can someone please point me to the right direction
Instead of calling the function in the render, I would rather put the component on the render and then call the fetch function on some lifecycle hook like componentDidMount.
This updates the state, hence re-rendering the component and the PictureOfTheDay... If the component does not work with an empty description etc which might be a cause of you wanting to make sure the fields are there, render it conditionally based on the needed information e.g {this.state.picDayFullDescription && ...}
// App.js
componentDidMount() {
this.showPicture();
}
showPicture = async () => {
const response = await picOfTheDay.get("", {
params: {
date: this.date,
hd: true,
api_key: "KEY",
},
});
this.setState({ picDayFullDescription: response });
}
render() {
return (
<div>
<PictureOfTheDay
date={this.state.date}
picture={this.state.picDayFullDescription.url}
description={this.state.picDayFullDescription.explanation}
/>
</div>
);
}

Why am I getting an error : TypeError: Cannot read property 'map' of undefined?

Getting an error: TypeError: Cannot read property 'map' of undefined. Before reloading the page it's work fine. But when I'm reloading the page getting an error. I want to get object values from array.
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {fetchData} from '../../actions/fetchData';
class Menu extends Component {
componentDidMount() {
this.props.fetchData();
}
render() {
const {data, isFetching} = this.props.data;
if (isFetching) {
return (
<View>
<ActivityIndicator size={'large'} />
</View>
);
} else {
return (
<View
style={{
flex: 1,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
}}>
<Text>
{data.categories.map(nm => nm.name)}
{/* {console.log("data",data.categories.map(nm => nm.name))} */}
</Text>
</View>
);
}
}
}
function mapStateToProps(state) {
return {
data: state.data,
};
}
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({fetchData}, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Menu);
I'm not a react-native developer, but have working small experience on react. Here what I can understand as given below:
this.state = {
data: this.props.data,
};
In above code in constructor, first initialize with state.data, when class instance is called and it will be undefined. Because when first class is called, this.props.data is undefined.
componentDidMount() {
this.props.fetchData();
}
After constructor's task complete, above code will be executed and it's data is shown in console.log. But returned data is never assign to any variable. That means, after fetching data, this.state.data still is undefined.
so when comes to executing <Text>{this.state.data.data.categories.map(nm => nm.name)}</Text> , this.state.data will be undefined`. To solve this problem, you can try following code:
class Menu extends Component {
componentDidMount() {
this.props.fetchData();
}
render() {
return (
<View>
<Text>{this.props.data.data.categories.map(nm => nm.name)}</Text>
</View>
);
}
}
And one last thing, I strongly recommend that, you learn react development life-cycle. Thanks
I've got this problem before and i solved it for mapping through images array , because fetching data is asynchronous it seems like data is not available at beginning of rendering and causes of err when mapping , You should handle your app and prevent rendering before data is set into the state , so implement a checker to see data is completely available in state and then let render , it's the only solution and nothing else

How to Get a specific question by Id in React

I have a question concerning Mern stack. I have a program which is similar to stackOverflow, where you post a question and someone can reply. At the moment my program is able to post questions and also get a list of all questions. I have a link at each and every questions,so that when you click at any of the questions it should open that specific question. The id of the questions is visible at the rout e.g http://localhost:3000/link/5cae2dda9723ad157c085370. The problem am having is to get the content of that specific question
//*this code is able get the list of all questions*//
import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import { EMLINK } from "constants";
const Question = props => (
<tr>
<td>{props.question.author_name}</td>
<td>{props.question.question_title}</td>
<td>{props.question.question_input}</td>
<td>
<Link to={"/link/" + props.question._id}>comment</Link>
</td>
</tr>
);
class QuestionList extends Component {
constructor(props) {
super(props);
this.state = { questions: [] };
}
componentDidMount() {
axios
.get("http://localhost:4000/questions/")
.then(response => {
this.setState({ questions: response.data });
})
.catch(function(error) {
console.log(error);
});
}
questionList() {
return this.state.questions.map(function(currentQuestion, i) {
return <Question question={currentQuestion} key={i} />;
});
}
render() {
return (
<div>
<h3>Question List</h3>
<table className="table table-striped" style={{ marginTop: 20 }}>
<thead>
<tr>
<th>Name</th>
<th>Title</th>
<th>Question</th>
<th>Action</th>
</tr>
</thead>
<tbody>{this.questionList()}</tbody>
</table>
</div>
);
}
}
export default QuestionList;
*/The below code is the one that i need to only show one specific question by ID*//
import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
const Questioners = props => (
<tr>
<td>{props.question.author_name}</td>
<td>{props.question.question_title}</td>
<td>{props.question.question_input}</td>
</tr>
);
class QuestionLink extends Component {
constructor(props) {
super(props);
this.state = {
author_name: "",
question_title: "",
question_input: ""
};
}
render() {
return (
<div>
<h3>Question List</h3>
<table className="table table-striped" style={{ marginTop: 20 }}>
<thead>
<tr>
<th>Name</th>
<th>Title</th>
<th>Question</th>
</tr>
</thead>
<tbody>{}</tbody>
</table>
</div>
);
}
}
export default QuestionLink;
I've done the following in these scenarios:
Take the ID as a parameter to the Component (in this case, QuestionLink)
Retrieve the question from your REST API as a get for the particular resource (with ID) in your ComponentDidMount
When mounting your react app (top-level component), retrieve the Id from the url. I prefer to use a query string
import { parse } from "querystring";
let values = parse(window.location.search.substring(1));
And then mount <QuestionLink questionId={values["questionId"]} />
EDIT: I haven't used template engines for this, but it should be well suited for this kind of work. You can use something like pug for the server side rendering, pass the id to the view from your middleware, and render to a react component. I'd probably only do this if I did this sort of processing extensively and/or needed information that only the server had.
Thanks for help, i made it work. i solved the issue as follow
<Route
path="/link/:id"
render={props => <QuestionLink {...props} />}
/>
this.state = {
currentQuestion: {}
};
componentDidMount() {
axios
.get("http://localhost:4000/questions/")
.then(response => {
this.setState({
currentQuestion: response.data.find(elm =>
elm._id == this.props.match.params.id
)
});
})

Cannot access key values in an object with React

Working on a project in React using a MongoDB database. I am trying to access key values in objects, but I get an error when I try to access them. I can access the objects themselves, but as soon as I use dot notation, React crashes and says TypeError: Cannot read property 'title' of undefined. The only instance I can get the data is when I console log in my fetchData() function before it goes through componentDidMount.
class TimelineContainer extends Component {
constructor(props){
super(props)
this.state = {
lifeEvents: [],
currentUser: auth.currentUser
}
}
componentDidMount(){
this.fetchData()
}
fetchData(){
LifeEventModel.all().then( (res) => {
this.setState ({
lifeEvents: res.lifeEvents,
uid: res.lifeEvents.uid,
currentUser: auth.currentUser
})
console.log(this.state.lifeEvents[0].title)
})
}
Link to database backend hosted on heroku. Link to my github repo.
render(){
console.log(this.state.lifeEvents[0].title)
console.log(this.state.lifeEvents);
return (
<div className='timelineContainer'>
{
(this.state.currentUser != null) ?
<div>
<CreateLifeEventForm
currentUser= {this.state.currentUser}
onCreateLifeEvent={this.createLifeEvent.bind(this)} />
<Timeline
currentUser= {this.state.currentUser}
lifeEvents={this.state.lifeEvents}
onDeleteLifeEvent={this.deleteLifeEvent.bind(this)}
onUpdateLifeEvent={this.updateLifeEvent.bind(this)}
/>
</div> :
<section className="col-md-4 col-sm-12 add-event">Log in to add a life event</section>
}
</div>
)
}
}
render method above. First console log throws the error. Second one does not.
it is possible that since you are not fetching your data asynchronously, the initial result this.state.lifeEvents will be null. so you have to first check for the null value until react updates the state and re-renders.
try this out:
renderView = () => {
return (this.state.lifeEvents === null)? <div>Loading...</div> :
(<div>
<CreateLifeEventForm
currentUser= {this.state.currentUser}
onCreateLifeEvent={this.createLifeEvent.bind(this)} />
<Timeline
currentUser= {this.state.currentUser}
lifeEvents={this.state.lifeEvents}
onDeleteLifeEvent={this.deleteLifeEvent.bind(this)}
onUpdateLifeEvent={this.updateLifeEvent.bind(this)}
/>
</div>)
};
render(){
return (
<div className='timelineContainer'>
{
(this.state.currentUser != null) ? this.renderView() :
<section className="col-md-4 col-sm-12 add-event">Log in to add a life event</section>
}
</div>
)
}

Categories

Resources