React component to output database info - javascript

I've making a recipe website and having trouble putting to words what I'm trying to do.
I have a component (home.js) which I'm trying to display different recipe posts on.
My thought was that I could make a component called recipe.js that would just have the structure of how a recipe post would be laid out. Then, all the recipe information would be displayed in that structure as it pulls all the recipe info from my database. This way I wouldn't have to have an individual component for each recipe.
Am I right in going about this? I'm a bit lost as to how I'm meant to do this or even what I would google to help accomplish this.
I'd be grateful for a push in the right direction.

I'm not a total React pro but I think a useFetch would work: it would pull info from the database using the props passed in.
import React from 'react';
import { useFetch } from 'react-async';
export const Recipe = (props) => {
const { data, error } = useFetch(`https://swapi.co/api/people/${id}/`, {
headers: { accept: "application/json" },
})
if (error) return error.message
if (data) return (<div className="recipe"></div>)
return null;
}

Related

How do i fetch json from a url and display json content on my js page

Im making a custom MS Teams app and in the app im trying to fetch a json from a url to then display the contents later. However, the fetch is failing. My goal is to fetch a list of data from a supplied url and then displaying it in the Tab within my teams app, which would be here: Where i want my json content to show up
As you can probably tell, i dont have any experience with javascript at all, but the custom MS teams app wants javascript...
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import React from 'react';
import './App.css';
import * as microsoftTeams from "#microsoft/teams-js";
/**
* The 'GroupTab' component renders the main tab content
* of your app.
*/
class Tab extends React.Component {
constructor(props){
super(props)
this.state = {
context: {}
}
}
//React lifecycle method that gets called once a component has finished mounting
//Learn more: https://reactjs.org/docs/react-component.html#componentdidmount
componentDidMount(){
// Get the user context from Teams and set it in the state
microsoftTeams.getContext((context, error) => {
this.setState({
context: context
});
});
// Next steps: Error handling using the error object
}
componentDidMount() {
fetch('http://example.com/movies.json')
.then(response => response.json())
.then(data => console.log(data));
}
render() {
var jsondata = data;
let userName = Object.keys(this.state.context).length > 0 ? this.state.context['upn'] : "";
return (
<div>
</div>
);
}
}
export default Tab;
So to sum it all up, how do i fetch my json from a url and display the content of that json on my tab.js page within teams?
Thanks in advance for any help.
While I can't speak to how the Teams API works, I can help you understand how to render things from a json API in your react component.
In your componentDidMount function, your example is sending and receiving the response from the API. To render this response, we need to assign the data to your component's "state" and then use that to render it in HTML.
This will be pretty simple. First, you need to extend your component's state, in a similar manner as you've done for context. Do this first in the constructor, where we'll declare an initial state of an empty object (I'll name it content but you can use whatever name makes most sense):
// inside the constructor() function
this.state = {
context: {},
content: {}
}
In React, we use setState to update this state object state when something changes, like on a lifecycle method such as componentDidMount. You just need to call this setState again when you want to change the state object from its initial value to something else. In our case, when we receive the data from the API.
setState takes whatever you provide it and merges it into the state object, so you only should declare anything you want to change. Anything else not declared will remain unchanged.
So, in componentDidMount, we can make a small change to do something with data when it arrives:
componentDidMount() {
fetch('http://example.com/movies.json')
.then(response => response.json())
.then(data => {
this.setState({
content: data
})
});
}
This is basically saying:
once the component has mounted, make a call to fetch from the API
then, with that response, take the json from the body
and then, assign the json "data" into our component's state object under the key of content.
You can then do things with this data by calling this.state.content. I'm not sure what format the data will come in, but whatever json object arrives back from the API will be stored under this.state.content.
As an example, imagine we get a simple object back from the API that looks like this { title: "Tab title" }. It means that, on a successful call to the API, our state object will look like this:
{
context: "whatever you have here", // whatever you have here, I don't know this
content: { title: "Tab title" }
}
When this state object is updated, react will trigger a new render of the component.
So, to make it appear in our component, we need to use this state in our render function (we wrap things in curly braces if they need to be dynamically rendered rather than hardcoded):
render() {
return (
//... the rest of your function
<div>{this.state.content.title}</div>
);
}
As you might have guessed, this will show the title inside a div, if the title exists.
Eventually, you should consider handling the state of the component before that API call has resolved itself. The lifecycle method componentDidMount will be called after the component is mounted, and because you're hitting an API, there will be something rendered to the DOM before the API call resolves itself. In my example, it'll be just be an empty div, and then it'll appear when the state updates and the render function is called again.
You could do this more effectively by extending your state object to see whether the API response is done (you'd update this in the same place you set the content), and you could render the UI conditionally on this.
The official docs on lifecycle methods will help you understand this pattern more.
Good luck!
Well, you can rely on #Josh Vince for an explanation as he did it perfectly, I will just write the code a bit cleaner for you.
Let's create 2 methods that will set the state with respective data and then simply call the state values and render the following as per your wish.
import React, {Component} from 'react';
import './App.css';
import * as microsoftTeams from "#microsoft/teams-js";
class Tab extends Component {
this.state = {
context: {},
movies: null
}
getContext = () => {
try {
microsoftTeams.getContext((context) => this.setState({context}));
}
catch(error){
console.log('ERROR ->', error);
throw error;
}
}
fetchMoviesData = () => {
try {
fetch('http://example.com/movies.json')
.then(response => response.json())
.then(data => this.setState({movies: data}));
} catch(error){
console.log('ERROR ->', error);
throw error;
}
}
componentDidMount() {
this.getContext();
this.fetchMoviesData();
}
render() {
let {movies, context} = this.state;
const jsondata = movies;
let userName = Object.keys(this.state.context).length ? context['upn'] : "";
return <>JSONDATA: {jsondata}, USERNAME: {userName}</>
}
}
export default Tab;

How to render user list in React-Firebase

I'm still learning React and I'm trying to make a "design review app" where users signup as customers or designers and interact with each other.
I made the auth system and made sure that while signing up every user would get also some attributes in the firebase database.
Therefore, in my DB, I have a 'users/' path where every user is saved by uid.
Now I'm able to render a different dashboard if you're a customer or a designer.
In my customer dashboard, I just want to render a list of designers (and clicking on them go to their projects).
However, I'm having so many problems trying to get this stuff to work!
In the following code, I'm trying to fetch the users from the db and add their uid to an array.
Later I want to use this array and render the users with those uids.
import firebase from "firebase/app";
import "firebase/database";
export default function CustomerContent() {
const[designers, setDesigners] = useState([]);
function printUsers (){
var users = firebase.database().ref('/users/');
users.on('value', (snapshot)=>{
snapshot.forEach((user)=>{
console.log(user.key)
firebase.database().ref('/users/'+user.key).on('value', (snapshot)=>{
var role = snapshot.val().role
console.log(role)
if(role === 'designer'){
const newDesigners = [...designers, user.key];
setDesigners(newDesigners);
}
})
})
})
}
useEffect(() => {
printUsers();
console.log(designers);
}, [])
return (
<div>
designer list
</div>
)
}
Now the problem with this code is that:
it looks like it runs the printUsers functions two times when loading the page
the array is empty, however, if I link the function to a button(just to try it), it seems to add only 1 uid to the array, and always the same (I have no idea what's going on).
ps. the console.log(user.key) and the console.log(role) print the right user-role combination
It's not a stupid question. Here's what I'd change it to (of course you'd remove the console.logs later though). It's hard to know if this will work perfectly without having access to your database to run it, but based on my last react/firebase project, I believe it'll work.
The first thing was that you reference /users/, when you only need /users. I'm not sure if it makes a difference, but I did it the latter way and it worked for me.
Secondly, you're calling firebase more than you need to. You already have the information you need from the first time.
Third, and this is small, but I wouldn't call your function printUsers. You're doing more than just printing them- you're making a call to firebase (async) and you're setting the state, which are much larger things than just print some data to the console.
Lastly, I would store the entire object in your designers piece of state. Who knows what you'll want to display? Probably at least their name, then possibly their location, background, an icon, etc. You'll want all of that to be available in that array, and possibly you'll want to move that array into redux later if you're app is big enough.
I also added some JSX to the bottom that gives a simple output of what you could do with the designers array for the visual aspect of your app.
import firebase from 'firebase/app';
import 'firebase/database';
export default function CustomerContent() {
const [designers, setDesigners] = useState([]);
function printUsers() {
var users = firebase.database().ref('/users');
users.on('value', (snapshot) => {
snapshot.forEach((snap) => {
const userObject = snap.val();
console.log(userObject);
const role = userObject['role'];
console.log(role);
if (role === 'designer') {
const newDesigners = [...designers, userObject];
setDesigners(newDesigners);
}
});
});
}
useEffect(() => {
printUsers();
console.log(designers);
}, []);
return (
<div>
<h2>The designer are...</h2>
<ul>
{designers.map((designerObject) => {
return <li>{designerObject.name}</li>;
})}
</ul>
</div>
);
}

How to declare array from API in place of hardcoded array?

I was given an example for some code that has an array hardcoded. Im looking to swap this out for my array that is pulled in from an API using graphql. Below is the code pen to the original example & another for what i've tried with no avail.
I'm pretty new to graphql & js so likely an amateur mistake, any pointers would be much appreciated!
Original code - https://codesandbox.io/s/nice-saha-gwbwv
My pen - https://codesandbox.io/s/quiet-wind-brq8s?file=/src/App.js
I would change your component structure to something like:
import React, { useState } from 'react'
import { graphql } from 'gatsby'
const YourPage = ({data}) => {
console.log('data is', data)
const [filters, setFilters] = useState({
type: "",
category: ""
});
//your calculations
return (
<div>
Your stuff
</div>
)
}
export const query = graphql`
query yourQueryName{
allStrapiHomes {
nodes {
type
category
}
}
}
`
export default YourPage
In your code, upon some critical imports, you are missing a few stuff from Gatsby. If you use a staticQuery, you will need to add a render mode to it. It may look a bit old-fashioned, it's better to use the useStaticQuery hook provided by Gatsby or adding a page query (my approach).
I've added a page query. Your data is under props.data.allStrapiHomes.nodes, destructuring props you omit the first step, so your data will be at data.allStrapiHomes.nodes. Both type and category will be an array if they are set like this in the Strapi back-end.

this.state.persons.map is not a function but persons is already an array

It's my first time working with React and I'm having some trouble with starting to use Axios. I watched a video, a very simple practical tutorial that showed how to use a get function, but I think something went wrong because even following the same exact steps I still get the error "this.state.persons.map is not a function". I want to stress the fact that the author of the video uses this exact same JavaScript code, and for him it works. Any explanation?
Here's the whole code for reference:
import React from "react";
import axios from "axios";
export default class personList extends React.Component{
state = {
persons: [],
};
componentDidMount(){
axios.get(`https://jsonplaceholder.typicode.com`)
.then(res =>{
console.log(res);
this.setState({persons: res.data});
});
}
render() {
return (
<ul>
{this.state.persons.map(person => <li key={person.id}>{person.name}</li>)}
</ul>
)
}
}
I looked around for an answer, but every other case that has been presented is either too different (using set arrays, json and whatnot) or it refers to a string used instead of an array, which causes the error, and obviously it's not my case.
You are making a GET request at https://jsonplaceholder.typicode.com which returns the whole webpage. If you want to fetch the users, use this URL instead: https://jsonplaceholder.typicode.com/users

React Axios - JSON Get response isn't displaying from render() - Riot API

I starting learning React a couple days ago and Axios today. I've spent the last 4+ hours watching/reading tutorials and I just can't figure this out.
I'm trying to create a simple stats website for League of Legends using Riot's API. Below you can see my constructor, componentDidMount, and render functions. I feel like I'm doing 1 of 3 wrong or most likely all 3. I'm calling this Get, which returns the JSON below. I want to access the "name" and "accountId".
{
"profileIconId": 3270,
"name": "Doublelift",
"puuid": "SrvIz_3Xa05InF_hTjwq1v8iB6lqNXz0SEc_5vhOFYlScrZOg8pSM9Si_UdPGAD9UYGhaRWHBeBGrw",
"summonerLevel": 155,
"accountId": "iNc_SUPKq-ckcANeC36Yn18Y0XSofK3ShBQg_h5wivC0Bg",
"id": "DjnxZhsTjgNhv3sMZMMJjlCUqAskiMfP6bP7GIcWovbwR1k",
"revisionDate": 1580499454000
}
I should note that I made my API key default. It's stored in my index.js file. Is this secure?
axios.defaults.headers.common['Authentication'] = 'API-Key-randomlettersandnumbers';
Here's my code. In render() when I type summonerDetail.[field] it recognizes the fields that are there shown in the JSON response above. Maybe my render is wrong causing it not to display? And yes I know "accountID" isn't in my render. I figured I'd start small with just "name". I will eventually need to use "accountID" for a different Get.
import React from 'react';
import axios from 'axios';
export default class GetBySummonerName extends React.Component {
constructor(props){
super(props);
this.state = {
summonerDetails: []
};
}
// https request to perform Get
componentDidMount() {
axios.get('https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/doublelift')
.then(res => {
console.log(res);
this.setState({ summonerDetails: res.data});
})
}
render() {
return (
<div>
{ this.state.summonerDetails.map(summonerDetail => <h1>{summonerDetail.name}</h1>)}
</div>
)
}
}
To display the "name" on the website I import the above class into App.js. Only problem is it's not working. I have the console.log(res); in my ComponentDidMount(), but I don't know how to view the console in Atom. I don't need any headers in my componentDidMount() because the "summonerName" is in the Get URL. The rest of the headers are auto-generated on Riot's side. Please help :)
You don't need to map. If you are receiving the object like the following in res.data
{
"profileIconId": 3270,
"name": "Doublelift",
"puuid": "SrvIz_3Xa05InF_hTjwq1v8iB6lqNXz0SEc_5vhOFYlScrZOg8pSM9Si_UdPGAD9UYGhaRWHBeBGrw",
"summonerLevel": 155,
"accountId": "iNc_SUPKq-ckcANeC36Yn18Y0XSofK3ShBQg_h5wivC0Bg",
"id": "DjnxZhsTjgNhv3sMZMMJjlCUqAskiMfP6bP7GIcWovbwR1k",
"revisionDate": 1580499454000
}
Then replace this in you return statement.
<div>{ this.state.summonerDetails.name }</div>
Hope this works for you.
You can check the response of your API in your network tab or you can console.log your state variable this.state.summonerDetails inside render method. If the response you are receiving is object, then you don't need to map over it. If it is an array then you have to iterate over it using map and extract the name property.

Categories