I'm new to React.
I have the code below with a function, but when I run it, it returns an error:
TypeError: renderJson[item.node] is not a function.
How can I fix the renderJson function?
export const readItem = item => {
printlog(item);
return renderJson[item.node](item);
};
const renderJson = {
"heading": item => <h1>{item.map(item => readItem(item))}</h1>
};
If you're trying to create a single React functional component that takes a JSON, and outputs the items in the JSON as a header, it would be more like this:
// If you're getting this JSON from an external source using something like a GET request, put the request inside a "useEffect()" hook
const myJson = {
"heading": ["My First Header", "My Second Header"]
};
export const Header = () => {
console.log(myJson);
return <h1>{myJson.heading.map(header => header}</h1>
};
I apologize if this is a misinterpretation of your question. If it is, any additional details would be helpful.
Related
I am trying to display some JSON data that I receive from my backend. I first have a useEffect which retrieves the JSON data:
const [backendData, setBackendData] = useState(null)
useEffect(() => {
const fetchUserData = async () => {
const response = await fetch('http://localhost:5000/api/userData/')
const json = await response.json()
// check if response is ok
if (response.ok) (
setBackendData(json)
)
}
fetchUserData()
console.log(backendData, 'hi')
}, [])
And then in my JSX code I want to display the _id of the object which has a structure that looks like this:
by using this line of code:
{backendData && backendData.map((userData) => {
<p key={userData._id}>{userData._id}</p>
})}
I am unsure as to why this line of code doesn't work though because I don't see any output on the next.js page. I am able to receive the backend data as I see the object in my console when I log it but when I try mapping it, it doesn't work. Does anyone know why?
I figured out why, you have to return a value when you map in next.js so the solution would be:
{backendData && backendData.map((userData) => {
return (
<p key={userData._id}>{userData._id}</p>
)
})}
Hello and thanks for the help in advance.
I'm trying to get my Nuxt app to automatically loop through my Woocommerce API automatically so it can generate the pages without much work.
How do I get the loop to function. Right now, I'm having issues and get a Nuxt Fatal Error:
TypeError: Cannot read property 'forEach' of undefined
Screenshot of Error + Code
I'm using Woocommerce API and, as you can see in the screenshot above, the Woocommerce code is imported into this code I need help with using a standard import.
import WooCommerce from './woocommerce.js';
generate: {
routes() {
WooCommerce.get("products").then((response) => {
let totalPages = response.headers['x-wp-totalpages'];
let page = 1;
while(page <= totalPages) {
WooCommerce.get("products", page).then((response) => {
response.data.map(product => {
return '/product/' + product.slug
});
})
page++;
}
})
}
},
You are not returning any routes in your routes function. Because of that, nuxt fails as it tries to iterate over them in a later step.
Assuming your way of accessing your API is correct, you would only need to add an array to which you push your routes and then return it.
I'm usually using async/await, which is why my code looks slightly different. It is a bit easier in this case I think.
// Declare the routes function asynchronous
async routes() {
const productsResponse = await WooCommerce.get('products');
const totalPages = productsResponse.headers['x-wp-totalpages'];
// Add an array to collect your routes
const routes = [];
let page = 1;
while (page <= totalPages) {
const pagesResponse = await WooCommerce.get('products', page);
// The 'map' function returns the routes for this set of pages
const productRoutes = pagesResponse.data.map((product) => {
return '/product/' + product.slug;
});
// Push your routes to the created array-
routes.push(...productRoutes);
page++;
}
// Return your routes
return routes;
};
So I have a database that I can query using ExpressJS and NodeJS. The Database is a MySQL db. and the data within looks like this:
id: 1
username: 'someUsername'
email: 'randomEmail#email.email'
I want to somehow put the data from within the database into a JSON list and then map over it and show it to the user. Another option to achieve this, I reasoned, would be to populate the state of the app. I've thought of creating some class component, adding a mapStateToProps and assign the data returned from the queries to the state and then use the data from the state in the Reactapp itself. I am not so sure if that would be effective.
This is the minimum code example for a component that fetches data from your backend onLoad, and displaying the data using .map, without using redux (mapstatetoprops)
const DisplayData = () => {
const [ data, setData ] = useState([]);
const fetchData = async () => {
const results = await fetch(url).then(res => res.json());
setData(data)
}
useEffect(() => {
fetchData()
},[])
return ( <div>
{ data.map(item => <p>{item.name}</p> }
<pre>
{ JSON.stringify(null, data, 4) }
</pre>
</div>
}
Well, the return data that you get from the SQL query is itself an array of objects,
Your answer lies in simply iterating over the returned data and assigning it to whatever object you like.
let queryResults = returnedQueryData // data returned from SQL query
let jsonarray = {}
for (row in queryResults) {
jsonarray[row.id] = {
id: row['id'],
username: row['username'],
email: row['email']
}
To access data from the JSON array use
Object.keys(jsonarray).forEach(e => {
// Here e is the object element from the JSON array
}
I reviewed previous posts and did not see anything that addresses this issue. I'm using a functional component/hook to fetch data from an open source api. The code works as long as I am only displaying 1 field from data.map in the return render. If I try to display more than one, I get the following error: Objects are not valid as a React child (found: object with keys {name, catchPhrase,bs}). If you meant to render a collection of children, use an array instead. DevTools says the error is in the list component. When all but one list element is commented out, I can see that the entire array is returned in DevTools, and the one list element will display. Adding an additional fields(list items) results in the error. Not sure what I'm doing wrong. Any help is appreciated.
import React, { useEffect, useState } from 'react';
function PeopleData() {
const [data, setData] = useState([]);
function GetData(){
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(response => setData(response))
}
console.log(data)
useEffect(() => {
GetData();
}, []);
return (
<div>
{data.map(item => <div key={item.id}>
<div>
<li>{item.name}</li>
{/* <li>{item.company}</li>
<li>{item.phone}</li>
<li>{item.email}</li> */}
</div>
</div>)}
</div>
)
}
export default PeopleData;
It's because you are trying to display company property from the response.
From the API:
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
This means that you have to display company.name, company.bs or company.catchPhrase.
Each object has the shape shown bellow, and the app is crashing because you are trying to render company which is an object, when it is expecting a string or node. So you should use item.company.name instead
{
id: 1,
name: "Leanne Graham",
...
company: {
name: "Romaguera-Crona",
catchPhrase: "Multi-layered client-server neural-net",
bs: "harness real-time e-markets",
},
};
You can also take advantage of the await/async syntax instead of chaining together then statements like bellow. The execution of the line is promised before the beginning of the next line by means of the await operator
async function GetData() {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
const json = await response.json();
setData(json);
}
I have this working in a sandbox here https://codesandbox.io/s/throbbing-butterfly-dt2yy?file=/src/App.js
The company property is an object and an object can't be a child in React as it says in the error as well.
Objects are not valid as a React child (found: object with keys {name,
catchPhrase,bs})
The solution is to only show properties from the company object that you may be interested to show in the UI.
import React, { useEffect, useState } from 'react';
function PeopleData() {
const [data, setData] = useState([]);
function GetData(){
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(response => setData(response))
}
console.log(data)
useEffect(() => {
GetData();
}, []);
return (
<div>
{data.map(item => <div key={item.id}>
<div>
<li>{`Name: ${item.name}`}</li>
<li>{`Company: ${item.company.name}`}</li>
<li>{`Phone: ${item.phone}`}</li>
<li>{`Email: ${item.email}`}</li>
</div>
</div>)}
</div>
)
}
export default PeopleData;
Item.company is an Object, that's why React throws an Error. You have to access the attributes of company. If you want to display all attributes of Company you could built a "For In" loop and and display them all too. I can show you an example if you need clarification.
As a little side note and tip, look into the useFetch hook. You will love it, especially if you have multiple components that fetch data like this.
I'm trying to display game information from the Steam API in a React Native Flatlist. I'm new to React and JSX, so a lot of what I'm reading doesn't make sense.
I want the Flatlist to display a list of game titles owned by a particular account. The data returned from Steam's API call (via fetch) looks like this:
{
"response": {
"game_count": 69,
"games": [
{
"appid": 220,
"name": "Half-Life 2",
"playtime_forever": 24,
"img_icon_url": "fcfb366051782b8ebf2aa297f3b746395858cb62",
"img_logo_url": "e4ad9cf1b7dc8475c1118625daf9abd4bdcbcad0",
"has_community_visible_stats": true,
"playtime_windows_forever": 0,
"playtime_mac_forever": 0,
"playtime_linux_forever": 0
},
{
"appid": 320,
"name": "Half-Life 2: Deathmatch",
"playtime_forever": 0,
"img_icon_url": "795e85364189511f4990861b578084deef086cb1",
"img_logo_url": "6dd9f66771300f2252d411e50739a1ceae9e5b30",
"has_community_visible_stats": true,
"playtime_windows_forever": 0,
"playtime_mac_forever": 0,
"playtime_linux_forever": 0
},
and so on. Since I'm trying to display a list of games by name, the name attribute is the only one I need.
The data lists each game as an anonymous object, so I can't access the properties within each game using dot notation like I normally would. I tried using a for loop to iterate through them, but that doesn't work either. From my research, it seems like people normally use an Array.map for this kind of thing, but I'm unclear if that can be used with Objects.
Another problem I've encountered is the Flatlist keyExtractor property. I know it's supposed to be an anonymous function that returns some unique index or property about each Flatlist item, for the purpose of making the structure more efficient and to allow it to track updates to the list. However, I have no idea how to create this function myself. I think the appid field from the JSON data would be a good candidate, but I'm not sure how to get that into the keyExtractor function.
So, to put it as a question: How would I go about displaying data from a JSON object containing anonymous sub-objects in a Flatlist, and how would I populate the keyExtractor of that list with a different data entry (the appid from that list?
Below is my starting code:
import React, {Component} from 'react';
import {FlatList, Stylesheet, Text, View} from 'react-native';
export default class App extends Component {
state = {
dataset: []
};
componentWillMount() {
this.fetchData();
}
fetchData = async () => {
const response = await fetch("<API URL>");
const json = await response.json();
//const data = json.map((item) => item.games.name);
var key = 0;
const data = json[games][0][name];
this.setState({ dataset: data });
}
render() {
console.log(this.state.dataset);
return (
<View>
<FlatList
data={this.state.dataset}
keyExtractor={(x, i) => i} //I have no idea what this does, or if it makes sense here.
//Where do x and i come from? (I got this from a tutorial video
//and this was glossed over)
renderItem={({ item }) => //Where does item come from?
<Text>
{item}
</Text>
}
/>
</View>
);
}
}
Alright, it seems you're having a few minor problems with understanding how FlatList works. Let me break it down for you.
Let's start with the Steam API request. In your example, you're first declaring dataset as an empty array in your state, then trying to update it with the result of a network request which is the way to go. The problem is, when you do json['games'][0]['name'] you're accessing the first item (index 0) of the games array and getting its name property and then setting that name as your dataset. Although you forgot the quotes around property names, it won't work. What you need to do instead is something like this:
fetchAllGames = async () => {
const steamResponse = await fetch("<API URL>");
const json = await steamResponse.json();
// We get all the games back from Steam in the form of an array
this.setState({ games : json.games });
}
We're now correctly updating the array inside our state with the data from the games array.
Let's move on to the keyExtractor and renderItem functions. The keyExtractor function is used to tell React about a unique identifier for each of your list items. In this case, this would be the appid property of a game. React then uses this unique ID to differentiate between items and determine which ones need updating. This function provides you with two parameters, namely the actual item and its index. Using these, we can then do something like this:
keyExtractor = (item, index) => {
return item.appid.toString();
}
We're now returning the appid property as a string (which is the type React expects key to be).
The renderItem function is a bit different, React is providing you with a parameter which contains your item plus a lot of other properties. Since we're only interested in the actual item, we're destructuring it using brackets like so: { item }. This is a technique commonly used in JavaScript to "extract" properties from objects. It is normally used like this:
const testObj = {
name : "John",
surname : "Doe"
}
const { name, surname } = testObj;
This way, you can directly refer to name and surname as if they were independent variables. Another way of doing this would be:
const testObj = {
name : "John",
surname : "Doe"
}
const name = testObj.name;
const surname = testObj.surname;
I hope this cleared some of the questions you might've been asking yourself! Here's the complete working code below. You may notice I moved some inline functions to class members, this is just a performance optimization to prevent the functions from being recreated on every render, you can ignore that.
import React, { Component } from 'react';
import { FlatList, Text } from 'react-native';
export default class App extends Component {
state = {
games : []
};
componentDidMount() {
this.fetchAllGames();
}
fetchAllGames = async () => {
const steamResponse = await fetch("<API URL>");
const json = await steamResponse.json();
// We get all the games back from Steam in the form of an array
this.setState({ games : json.response.games });
}
keyExtractor = (item, index) => {
return item.appid.toString();
}
renderItem = ({item}) => {
return (
<Text>{item.name}</Text>
);
}
render() {
return (
<FlatList
data={this.state.games}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem} />
);
}
}
EDIT #1 - As pointed out by the OP, I made a typo and corrected it. I also changed the JSON object to reflect the response property.