React fetch Firebase get unique key value - javascript

does anyone know how to get unique key value from firebase database? i want to store it inside state and print it into console.log.
this is example of unique key
this is the code, i just want to show it in console
import React, { Component } from "react";
export class Test extends Component {
constructor(props) {
super(props);
this.state = {
newId: ""
};
}
componentDidMount() {
fetch("https://redditclone-project.firebaseio.com/data.json", {
method: "get",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
}
})
.then(res => res.json())
.then(res => {
console.log(res);
});
console.log('value key, ex:-LzpvyLJnKgDllnTE-eW');
}
render() {
return <div></div>;
}
}
export default Test;
thanks
edit : inside res
and added my firebase link

If you only want to print the keys from the JSON, you can use Object.keys():
.then(res => res.json())
.then(res => {
console.log(Object.keys(res));
});
Since Object.keys() returns an array, you can then also use for example Array.forEach() to loop over these keys.

Related

how to change state value in helper function file in react js

I have functions.js file and it export one function that I want to use in many files.
functions.js
import { API_URL } from "./index";
export const getData = (skip = 0, params = "") => {
this.setState({
loading: true
});
fetch(`${API_URL}items?limit=5&skip=${skip}${params}`, {
method: "GET",
credentials: "include"
})
.then(res => res.json())
.then(res => {
if (res.result.length > 0) {
let array = [];
res.result.map(item => {
let obj = item.data;
obj = Object.assign({ id: item._id }, obj);
array.push(obj);
});
this.setState({
records: array,
loading: false
});
} else {
this.setState({
next: true,
loading: false,
records: []
});
}
})
.catch(err => {
this.setState({
loading: false
});
});
};
hear this is function.js file that gets data from API and set in the state,
now, I want to use this function in items.js
items.js
import { getData } from "./../../config/functions";
import React from "react";
class Customers extends React.Component {
constructor(props) {
super(props);
this.getData = getData.bind(this);
}
componentDidMount() {
this.getData();
}
...
}
Error
TypeError: Cannot read property 'setState' of undefined
I fount this answer How to use state of one component in another file in reactjs? but it did not work for me so help me to change app.js file state from my functions.js file.
You're trying to re-bind this on an arrow function, which you cannot do. Check out this other SO question/answer for more details, but that's your problem. I'm going to edit this post with a suggestion of a more idiomatic way to write this in React.
Edit: OK I wanted to get you an answer quickly so you could unblock yourself and learn a bit more about arrow functions and this binding.
But more than just fixing this, you could improve this code significantly if you separate your api requests from your component. Right now you're mixing them up by trying to set state in your function that fetches data.
import { API_URL } from "./index";
export const getData = (skip = 0, params = "") => {
this.setState({
loading: true
});
fetch(`${API_URL}items?limit=5&skip=${skip}${params}`, {
method: "GET",
credentials: "include"
})
.then(res => res.json())
.then(res => {
// no need to declare an array and then push to it,
// that's what map is for. It will return a new array.
return res.result.map(item => {
// can also be written as return { ...item, id: item._id }
return Object.assign({ id: item._id }, obj)
});
});
// no need to catch here, you can do error handling in your component
};
import { getData } from "./../../config/functions";
import React from "react";
class Customers extends React.Component {
constructor(props) {
super(props);
this.fetchData = this.fetchData.bind(this);
}
componentDidMount() {
this.fetchData();
}
fetchData() {
getData()
.then((results) => {
this.setState({
next: results.length === 0,
records: results,
loading: false
});
})
.catch((err) => {
this.setState({ loading: false })
});
}
...
}

React not re-rendering when setState following API calls

I have been struggling to understand what is going wrong with this simple todo list front end React app, which should interact with an express API.
my React code is:
import React, {Component} from 'react';
class App extends Component {
constructor(){
super();
this.state = {
todos:[],
currentItem: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleADDButton = this.handleADDButton.bind(this);
this.deleteItem = this.deleteItem.bind(this);
this.updateTodo = this.updateTodo.bind(this);
}
componentDidMount(){
fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/list')
.then(res => res.json())
.then((todosList) =>
{this.setState({'todos': todosList});
});
}
handleChange(event){
this.setState({currentItem: event.target.value});
}
handleADDButton(event){
fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/post', {
method: 'POST',
headers:{'Content-type': 'application/json'},
body: JSON.stringify({title: this.state.currentItem})
});
}
deleteItem(x){
fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/' + x, {
method: 'DELETE',
headers:{'Content-type': 'application/json'}
})
}
updateTodo(y){
fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/' + y, {
method: 'PUT',
headers:{'Content-type': 'application/json'},
body: JSON.stringify({title: this.state.currentItem})
})
}
render() {
return(
<div>
<h1> Todo List </h1>
<ul>
{this.state.todos.map((todo) => <li> {todo.title}
<button type="button" onClick={() => this.deleteItem(todo.key)} >x</button>
<button type="button" onClick={() => this.updateTodo(todo.key)}>update</button> </li>)}
</ul>
<input type="text" value={this.state.currentItem} onChange={this.handleChange} />
<button type="submit" onClick={this.handleADDButton}>ADD</button>
</div>
)
}
}
export default App
The calls do update the API, and if I manually refresh the page, the React app picks up on the new data coming through from the API. However, when clicking the buttons it doesn't re-render by itself.
Say for example I click the ADD Button. It sends an OPTIONS to which I get back a 200 code, a POST which also comes back with a 200 and only sometimes, a GET with a 200. There is no pattern in when it performs the last GET call and also there is no pattern in when it re-renders following a button click. To obtain the latest data I always have to refresh.
Don't know what to make of this and have been stuck for days.
I think there is no state update on button actions
try to add a state updates for the actions same as componentDidMount
For ex:
handleADDButton(event){
event.preventDefault();
fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/post', {
method: 'POST',
headers:{'Content-type': 'application/json'},
body: JSON.stringify({title: this.state.currentItem})
}).then(res => res.json())
.then((data) => {
this.setState((prevState) {
const todos = [...prevState.todos, data.todo];
return {
todos: todos
}
})
});
}
In this case you have to return the new todo which will catch in data.todo
And for delete action
deleteItem(x){
fetch('http://ec2-x-xx-xx-xxx.eu-west-2.compute.amazonaws.com:3001/' + x, {
method: 'DELETE',
headers:{'Content-type': 'application/json'}
}).then(res => res.json())
.then((data) => {
this.setState((prevState) {
const newTodos = prevState.todos.filter(t => t.key !== x);
return {
todos: newTodos
};
})
});
}
These codes are not tested.
actually you don't have any state update in your code. you have to use "setState" when fetching data from API. I recommended learning arrow function and Hooks and use somethings like AXIOS to manage API calls.

how post props redux React

I would like to explain my problem of the day.
I can't post "this.props.total",
I do not understand how to post a props, can you help me pls?
currently the props works correctly.
import React, { Component } from 'react';
import { CardText, } from 'reactstrap';
import { connect } from 'react-redux'
class thisPropsFortotal extends Component {
handleSubmit = (e) => {
e.preventDefault();
const config = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({this.props.total}),
};
const url = entrypoint + "/alluserpls";
fetch(url, config)
.then(res => res.json())
.then(res => {
if (res.error) {
alert(res.error);
} else {
alert(`ajouté avec l'ID ${res}!`);
}
}).catch(e => {
console.error(e);
}).finally(() => this.setState({ redirect: true }));
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<button type="submit">Add</button>
</form>
<CardText>{this.props.total} € </CardText>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
total: state.addedItems.reduce((acc, item) => { return acc + (item.quantity *
item.price) }, 0)
//addedItems: state.addedItems
}
}
export default connect(mapStateToProps)(thisPropsFortotal)
Do you have an idea of how to fix this? Neff
You are attempting to stringify {this.props.total}, which is invalid syntax.
You can pass an object explicitely defining the total property like so:
body: JSON.stringify({total: this.props.total}),
Or, simply stringify the this.props object itself:
body: JSON.stringify(this.props),

How to get the data in a fetch before the component get mount?

I am trying to make a fetch from a local server in Node, but my problem is that when I call the render function of the component the array users from the state seems to be empty and therefore does not render the users on the screen as I would like, the weird thing is that the console.log(users) I have inside the fetch does bring me the data, but when I do it on the render does not bring me anything:
this is the code so far:
import React, { PureComponent } from "react";
import Nav from "./Nav";
import { IState, IProps } from "./Interfaces";
class Home extends PureComponent<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
users: [],
books: []
};
}
getUsers = async () => {
const response = await fetch(`http://localhost:5000/users`, {
headers: {
"Content-Type": "application/json"
}
});
const users = await response.json();
for (let user of users) {
this.state.users.push(user);
}
console.log(this.state.users);
};
getBooks = async (id: number) => {
const token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlciI6Implc3VzIiwiaXNBZG1pbiI6dHJ1ZSwiaWF0IjoxNTc2NjgzNTkwfQ.1FWmtj-fCsqSza_pwfewIpp3zQ50BxDagRTvrh5x3cU";
const response = await fetch(`http://localhost:5000/bookUser/${id}/books`, {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json"
}
});
const books = await response.json();
this.setState({ books });
};
onUserSelection = (id: number) => this.getBooks(id);
componentDidlMount() {
this.getUsers();
}
render() {
const { users } = this.state;
console.log(this.state.users);
return (
<div>
<Nav username={this.props.username} />
<h1>Hello {this.props.username}</h1>
<table>
<tbody>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
{users.map(u => (
<tr
key={u.user_id}
onClick={() => this.onUserSelection(u.user_id)}
>
<td>{u.user_id}</td>
{console.log(u.user_id)}
<td>{u.username}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
}
export default Home;
As previously mentioned in Sameer's comment, you want to avoid using push when setting state. Doing this will not trigger a re-render.
Instead of the this.state.users.push(user) you're doing, replace that (and the console.log following it) with this:
this.setState(prevState => ({
users: [...prevState.users, user]
}, console.log("updated users", this.state.users)));
A few things different here.
The first argument in setState takes in a function. There is an argument exposed in that function which is your previous state (prevState). Using the spread operator you can create a new array with the old users and all the new ones.
Secondly, due to the asynchronous nature of setState, you can't expect to run a console.log() right after a setState function. Instead, you can pass a callback function (console.log in this instance) as the second argument to setState & it will be fired when completed.
Use setState to populate users in state
this.setState({
users: users
})
and in render before map, do this
{
users.length>0 &&
users.map(u => ( <tr key={u.user_id} onClick={() => this.onUserSelection(u.user_id)} > <td>{u.user_id}</td> {console.log(u.user_id)} <td>{u.username}</td> </tr> ))
}

Cannot call the first element of a JSON object

I'm trying to access the first object from data[]. Then, grab the keys using Object.keys() but it gives me this error:
"TypeError: Cannot convert undefined or null to object".
I need the output to be an array of the keys.
import React, { Component } from 'react';
class CodecChart extends Component {
constructor(props) {
super(props);
this.state = {
post: [],
isLoaded: false,
}
}
componentDidMount() {
const url = 'https://jsonplaceholder.typicode.com/users';
fetch(url)
.then(result => result.json())
.then(post => {this.setState({ post: post })
})
}
render() {
const data = this.state.post;
// cannot reach the first object of data[]
var keys = Object.keys(data[0]);
return (
<div>
//output should be an array of the keys
<h5>{keys}</h5>
</div>
)
}
}
export default CodecChart;
The first time you try to access data[0], it's still empty:
this.state = {
post: [],
isLoaded: false,
}
and const data = this.state.post; means that data[0] is undefined.
it's only after the component is mounted, and the state is set correctly that data[0] is defined (or not, depending on what the API returns).
I found a way for it to work by adding another "then" so it can set the "keys" state right after the "posts" state was set. But I wonder if there is another way to make it more elegant. Thank you for trying to help.
constructor(props) {
super(props);
this.state = {
posts: [],
isLoaded: false,
keys: []
}
}
componentDidMount() {
const url = 'https://jsonplaceholder.typicode.com/users';
fetch(url)
.then(result => result.json())
.then(posts => {
this.setState({ posts: posts })
})
.then(_ => { this.setState({ keys: Object.keys(this.state.posts[0]) }) })
}
render() {
const keys = this.state.keys;
return (
<div>
<h5>{keys}</h5>
</div>
)
}

Categories

Resources