Error: Objects are not valid as a React child (found: [object Promise]).….. While getting data from supabase - javascript

I am having a problem while getting data from supabase .
Could any one help me
`
import Link from "next/link";
import { supabase } from "../../supabase"
async function Index(){
const { data, error} = await supabase.from("Employees").select("*")
return (
<>
<div className="container flex justify-center">
<h1>Employees</h1>
</div>
{data.map((index) => {
return (
<h1>{index.name}</h1>
)
})}
<Link href="/employees/addemployee">
<h1>Add employee</h1>
</Link>
</>
)
}
export default Index;
`
I tried using map, other function, and looked it up yet nothing works

The problem is how you are fetching the data. Try fetching your data inside an useEffect hook:
import Link from "next/link";
import { supabase } from "../../supabase";
import { useState, useEffect } from "react";
function Index() {
// const { data, error } = await supabase.from("Employees").select("*")
const [data, setData] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
let cancelFetch = false; // to avoid race conditions on React18
supabase
.from("Employees")
.select("*")
.then((res) => {
if (!cancelFetch) {
setData(res.data);
setError(res.error);
}
});
return () => {
cancelFetch = true;
};
}, []);
return (
<>
<div className="container flex justify-center">
<h1>Employees</h1>
</div>
{data.map((index) => {
return <h1>{index.name}</h1>;
})}
<Link href="/employees/addemployee">
<h1>Add employee</h1>
</Link>
</>
);
}
export default Index;
More info on fetching and useEffect here: https://beta.reactjs.org/apis/react/useEffect#fetching-data-with-effects

Your source code is invalid. React components should always be a function (or class) that returns a react object. it does not accept a promise that returns a react object.
You will probably want to use react's useEffect to solve this problem:
import { useState, useEffect } from "react";
import Link from "next/link";
import { supabase } from "../../supabase"
async function Index(){
const [data, setData] = useState()
const [error, setError] = useState()
useEffect(() => {
supabase.from("Employees").select("*")
.then(data => setData(data))
.catch(err => setError(err))
}, [])
return (
<>
<div className="container flex justify-center">
<h1>Employees</h1>
</div>
{data.map((index) => {
return (
<h1>{index.name}</h1>
)
})}
<Link href="/employees/addemployee">
<h1>Add employee</h1>
</Link>
</>
)
}
export default Index;

Your component cannot be async, because it returns a Promise and React doesn't like that.
There is a cool function on Next.js that allows you to fetch data asynchronously, try that:
function Index({ data }) {
return (
<>
<div className="container flex justify-center">
<h1>Employees</h1>
</div>
{data.map((index) => {
return (
<h1>{index.name}</h1>
)
})}
<Link href="/employees/addemployee">
<h1>Add employee</h1>
</Link>
</>
)
}
export default Index;
export async function getServerSideProps() {
const { data, error} = await supabase.from("Employees").select("*")
return {
props: {
data: data
}
}
}
More here: https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props

Based on the way you are fetching data, I believe you are using next13 and you are in app directory. When you rendered jsx
{data.map((index) => {
return (
<h1>{index.name}</h1>
)
})}
index refers to each element inside the data array. Most likely index.name is an object. that is why it is throwing that error.
console.log("index name",index.name)
If you are using async functional component, you should be using Suspense api. Create a separeate component maybe async Users, fetch the data inside this component, and when you want to display the users inside the Index
import {Suspense} from "react"
function Index(){
return (
<>
....
<Suspense fallback={ <h1>Users are loading...</h1>} >
<Users/>
</Suspense>
....
</>
)
}

You only use async component inside app folder and server component.

Related

React: Passing value to a functional component results in undefined value

I'm trying to pass values one by one to a functional component from array.map function. Unfortunately the component is not redering the value.
This is what I'm getting. There are room names stored in DB that should be printed here.
Homescreen.js
import React, { useState, useEffect } from "react";
import axios from "axios";
import Room from "../components/Room";
export default function Homescreen() {
const [rooms, setRooms] = useState([]);
const [loading, setLoading] = useState();
const [error, setError] = useState();
useEffect(async () => {
try {
setLoading(true);
const data = (await axios.get("/api/rooms/getallrooms")).data;
setRooms(data);
setLoading(false);
setError(false);
} catch (error) {
setLoading(false);
setError(true);
console.log(error);
}
}, []);
return (
<div>
{loading ? (
<h1>Loading...</h1>
) : error ? (
<h1>Error fetching details from API</h1>
) : (
rooms.map((room) => {
return (<div>
<Room key={room._id} room={room}></Room>
</div>
)
})
)}
</div>
);
}
Room.js (Funcitonal component that should print room names):
import React from "react";
function Room(room){
console.log(room.name)
return(
<div>
<h1>Room name: {room.name}.</h1>
</div>
)
}
export default Room;
The data is fetched correctly from db because if, instead of passing the value to component I print directly into my main screen, the values are printed.
In otherwords, in Homescreen.js, doing <p>{room.name}</p> instead of <Room key={room._id} room={room}></Room> print room names correctly.
So I reckon the problem is coming when I'm passing the values as props.
Any help is much appreciated. Thanks.
The parameter passed to a function component is the props object which contains the passed props, so you just need to grab props.room from there:
function Room(props){
console.log(props.room.name)
return(
<div>
<h1>Room name: {props.room.name}.</h1>
</div>
)
}
Or, with object destructuring:
function Room({ room }){
console.log(room.name)
return(
<div>
<h1>Room name: {room.name}.</h1>
</div>
)
}

How to pass data from child to parent and render content based on selected value in dropdown?

I am learning React as I am fetching data from Pokéapi to make a list component, card component, detail component and filter component. I am trying to make a filter so you can filter by pokémon type. Only the cards that also contain that type string should then render (Not there yet). So I am not sure if a) I should make a different call from API inside PokemonList depending on selected value or b) if I should compare the values and just change how the PokemonCard element is rendered inside PokemonList.js depending on the comparison. I managed to pass data from filter to the list component. I have then been trying to pass the type data from PokemonCard.js to the list component so that I can compare these two values but I find it hard to use callbacks to pass the type data from the card component, since I dont pass it through an event or something like that.
Which method should I use here to simplify the filtering? Make different API call or render PokemonCard element conditionally?
Is it a good idea to compare filter option to pokemon card's type in PokemonList.js? Then how can I pass that data from the card component since I don't pass it through click event?
Thankful for any ideas! I paste the code from list component that contains the cards, card component and filter component.
PokemonList component:
import { useState } from 'react';
import useSWR from 'swr';
import PokemonCard from './PokemonCard';
import PokemonFilter from './PokemonFilter';
import './PokemonList.css';
const PokemonList = () => {
const [index, setIndex] = useState(0);
const [type, setType] = useState('');
function selectedType(type) { // value from filter dropdown
setType(type)
console.log("handled")
console.log(type)
}
const url = `https://pokeapi.co/api/v2/pokemon?limit=9&offset=${index}`;
const fetcher = (...args) => fetch(...args).then((res) => res.json())
const { data: result, error } = useSWR(url, fetcher);
if (error) return <div>failed to load</div>
if (!result) return <div>loading...</div>
result.results.sort((a, b) => a.name < b.name ? -1 : 1);
return (
<section>
<PokemonFilter onSelectedType={selectedType} selectedPokemonType={type} />
<div className="pokemon-list">
<div className="pokemons">
{result.results.map((pokemon) => (
<PokemonCard key={pokemon.name} pokemon={pokemon} /> // callback needed??
))}
</div>
<div className="pagination">
<button
onClick={() => setIndex(index - 9)}
disabled={result.previous === null}
>
Previous
</button>
<button
onClick={() => setIndex(index + 9)}
disabled={result.next === null}
>
Next
</button>
</div>
</div>
</section>
)
}
export default PokemonList;
PokemonCard component:
import { Link } from "react-router-dom";
import useSWR from 'swr';
import './PokemonCard.css';
const PokemonCard = ({ pokemon }) => {
const { name } = pokemon;
const url = `https://pokeapi.co/api/v2/pokemon/${name}`;
const { data, error } = useSWR(url);
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
const { types, abilities } = data;
// types[0].type.name <---- value I want to pass to PokemonList.js
return (
<div className='pokemon-card'>
<div className='pokemon-card__content'>
<img
className='pokemon-card__image'
src={data.sprites.front_default}
alt={name}
/>
<div className='pokemon-card__info'>
<p className='pokemon-card__name'>Name: {name}</p>
<p className='pokemon-card__abilities'>Abilities: {abilities[0].ability.name}</p>
<p className='pokemon-card__categories'>Category: {types[0].type.name}</p>
</div>
</div>
<Link className='pokemon-card__link' to={{
pathname: `/${name}`,
state: data
}}>
View Details
</Link>
</div>
)
}
export default PokemonCard;
PokemonFilter component:
import './PokemonFilter.css';
import useSWR from 'swr';
const PokemonFilter = ({onSelectedType, selectedPokemonType}) => {
const url = `https://pokeapi.co/api/v2/type/`;
const fetcher = (...args) => fetch(...args).then((res) => res.json())
const { data: result, error } = useSWR(url, fetcher);
if (error) return <div>failed to load</div>
if (!result) return <div>loading...</div>
function filteredTypeHandler(e) {
console.log(e.target.value);
onSelectedType(e.target.value);
}
console.log(selectedPokemonType)
return(
<div className="pokemon-types__sidebar">
<h2>Filter Pokémon by type</h2>
<select
name="pokemon-type"
className="pokemon-types__filter"
onChange={filteredTypeHandler}
>
<option value="All">Filter By Type</option>
{result.results.map((type) => {
return (
<option key={type.name} value={type.name}> {type.name}</option>
)
})}
</select>
</div>
)
}
export default PokemonFilter;
Here is an example to improve, modify, ... I didn't test, it's just a visual example.
I don't know about useSWR sorry, I use axios in my example...
If you want to centralize all your API requests, you can create a useApi hook, on the internet you will find tutorials.
PokemonList.js
import React, { useState, useEffect } from 'react';
import axios from 'axios'; // or swr
import PokemonFilter from './PokemonFilter';
import PokemonCard from './PokemonCard';
export default function PokemonList() {
const [data, setData] = useState([]);
const [filter, setFilter] = useState('');
// Executed every first render
useEffect(() => {
getData();
}, []);
// Executed only when filter changes
useEffect(() => {
getDataByTypes(filter);
}, [filter]);
// Get data
const getData = async () => {
const uri = 'https://xxx';
try {
const response = await axios.get(uri);
setData(response.data...);
} catch (error) {
console.log(error);
}
};
// Get data by types
const getDataByTypes = async (filter) => {
const uri = `https://xxx/type/${filter}...`;
if (filter) {
try {
const response = await axios.get(uri);
setData(response.data...);
} catch (error) {
console.log(error);
}
}
};
return (
<div className="main">
<PokemonFilter filter={filter} setFilter={setFilter} />
<div className="container">
<div className="cards-container">
{data.map((d) => (
<PokemonCard key={d.name} data={d} />
))}
</div>
</div>
</div>
);
}
PokemonCard.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export default function PokemonCard({ data }) {
const [pokemons, setPokemons] = useState();
useEffect(() => {
getPokemons(data);
}, [data]);
// Get Pokemons
const getPokemons = async (data) => {
const uri = `https://xxx/pokemon/${data.name}/`;
try {
const response = await axios.get(uri);
setPokemons(response.data...);
} catch (error) {
console.log(error);
}
};
return (
<div>
{pokemons && (
<div className="card">
<img src={pokemons.sprites.front_default} alt={pokemons.name} />
<p>{pokemons.name}</p>
<p>{pokemons.abilities[0].ability.name}</p>
<p>{pokemons.types[0].type.name}</p>
</div>
)}
</div>
);
}
PokemonFilter.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export default function PokemonFilter({ filter, setFilter }) {
const [types, setTypes] = useState([]);
useEffect(() => {
getType();
}, []);
// Get Type
const getType = async () => {
const uri = 'https://xxx/type/';
try {
const response = await axios.get(uri);
setTypes(response.data.results....);
} catch (error) {
console.log(error);
}
};
const handleFilter = (e) => {
setFilter(e.target.value);
};
return (
<select onChange={handleFilter} value={filter}>
<option>Filter by type</option>
{types.map((type) => {
return (
<option key={type.name} value={type.name}>
{type.name}
</option>
);
})}
</select>
);
}

Getting undefined props in functional react components

How to pass the {requests} prop to the RequestRow component after executing the setRequests? My understanding is that the requests get initialized as undefined in the beginning and before being set with the asynchronously called object, it gets passed to the RequestRow component as undefined, and the error occurs.
import React, { useState, useEffect } from 'react';
import 'semantic-ui-css/semantic.min.css';
import Layout from '../../../components/Layout';
import { Button } from 'semantic-ui-react';
import { Link } from '../../../routes';
import Campaign from '../../../blockchain/campaign';
import { Table } from 'semantic-ui-react';
import RequestRow from '../../../components/RequestRow';
const RequestsIndex = ({ address }) => {
const { Header, Row, HeaderCell, Body } = Table;
const campaign = Campaign(address);
const [requestCount, setRequestCount] = useState();
const [requests, setRequests] = useState([]);
const getRequests = async () => {
const count = await campaign.methods.getRequestsCount().call();
setRequestCount(count);
};
let r;
const req = async () => {
r = await Promise.all(
Array(parseInt(requestCount))
.fill()
.map((_element, index) => {
return campaign.methods.requests(index).call();
})
);
setRequests(r);
};
useEffect(() => {
getRequests();
if (requestCount) {
req();
}
}, [requestCount]);
return (
<Layout>
<h3>Requests List.</h3>
<Link route={`/campaigns/${address}/requests/new`}>
<a>
<Button primary>Add Request</Button>
</a>
</Link>
<Table>
<Header>
<Row>
<HeaderCell>ID</HeaderCell>
<HeaderCell>Description</HeaderCell>
<HeaderCell>Amount</HeaderCell>
<HeaderCell>Recipient</HeaderCell>
<HeaderCell>Approval Count</HeaderCell>
<HeaderCell>Approve</HeaderCell>
<HeaderCell>Finalize</HeaderCell>
</Row>
</Header>
<Body>
<Row>
<RequestRow requests={requests}></RequestRow>
</Row>
</Body>
</Table>
</Layout>
);
};
export async function getServerSideProps(context) {
const address = context.query.address;
return {
props: { address },
};
}
export default RequestsIndex;
The RequestRow component is shown below. It takes in the {requests} props, which unfortunately is undefined.
const RequestRow = ({ requests }) => {
return requests.map((request, index) => {
return (
<>
<div>Request!!!</div>
</>
);
});
};
export default RequestRow;
The snapshot of the error is shown below:
I think React is trying to render your component before your promises resolve. If that's the case, all you need to do is set a default value (an empty array in your case) for your requests.
const [requests, setRequests] = useState([]);
May the force be with you.

Objects are not valid as a React child (found: [object Promise]) while rendering Firebase results

I am getting the following error:
Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
I am using context in react and having a problem with props as I have forEach loop in inner components to fetch data from the database.
I don't know how to render a collection by using an array here.
Here is the code to fetch data due to which the error is occurring:
import React, { useEffect, useState } from "react";
import { db } from "../services/firebase";
import style from "./css/dashboard.module.css";
import InputTask from "./InputTask";
import Task from "./Task";
const Tasks = ({ user }) => {
console.log("Tasks");
return (
<>
<div className={style.card}>
<InputTask user={user} />
</div>
{true
? db
.collection("Users")
.doc(`${user.email}`)
.collection("tasks")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data());
return (
<div className={style.card}>
<Task todo={doc} />
</div>
);
});
})
: null}
</>
);
};
export default Tasks;
Error's snapshot attached here
Your render method (part attached below) will not wait until .then is triggered. Instead, it will return the Promise as is. Thus the Error: Objects are not valid as a React child (found: [object Promise]) you mentioned.
{
true
? db
.collection("Users")
.doc(`${user.email}`)
.collection("tasks")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data());
return (
<div className={style.card}>
<Task todo={doc} />
</div>
);
});
})
: null
}
As this is an async operation, it's better if you use a state for this part. For instance, you can fetch the data when your component mounts (with a useEffect), put everything into a state (with useState), and render the state.
import React, { useEffect, useState } from "react";
import { db } from "../services/firebase";
import style from "./css/dashboard.module.css";
import InputTask from "./InputTask";
import Task from "./Task";
const Tasks = ({ user }) => {
const [tasks, setTasks] = useState([]);
// fetching data again when user changes
useEffect(() => {
db
.collection("Users")
.doc(`${user.email}`)
.collection("tasks")
.get()
.then((querySnapshot) => {
setTasks(querySnapshot);
})
}, [user]);
return (
<>
<div className={style.card}>
<InputTask user={user} />
</div>
{tasks.length
? tasks.map((task) =>
<div className={style.card}>
<Task todo={task} />
</div>
)
: null}
</>
);
};
export default Tasks;
You haven't imported useContext hook from react
Try this
import React, { useEffect, useState, useContext } from "react";
import { auth } from "../services/firebase";
export const AuthContext = React.createContext();
export const AuthProvider = (props) => {
const [loading, setLoading] = useState(true);
const [currentUser, setCurrentUser] = useState(null);
useEffect(() => {
auth.onAuthStateChanged((user) => {
setCurrentUser(user);
setLoading(false);
});
}, []);
if (loading) {
return <p>Loading...</p>;
}
// console.log(children);
return (
<AuthContext.Provider value={{ currentUser }}>
{props.children}
</AuthContext.Provider>
);
};

Foreach loop in return statement of react

I have fetched some information an API and now I am trying to show the information fetched from it. The information which I have fetched includes books_authors , books_id's , price and the dataset is quite large and I am unable to display this information from my following approach...can someone help me with it... I am new to react
This is what I have tried so far:
import React from "react";
import Head from './head';
function App(){
let s;
const proxy = 'http://cors-anywhere.herokuapp.com/';
const api = `${proxy}http://starlord.hackerearth.com/books`;
fetch(api)
.then(response =>{
return response.json();
})
.then(data =>{
console.log(data);
data.forEach((index) => {
s=index;
<Head s/>
});
});
return(
<Head />
);
}
export default App;
//the head component
import React from "react";
function Head(props){
return(
<div className="app">
<div className="heading">
<h1>BOOK_CAVE</h1>
<div className="heading_description">So many books...so
little time...</div>
</div>
<div className="author">{props.authors}</div>
<div className="id">{props.bookID}</div>
<div className="price">{props.price}</div>
</div>
);
}
export default Head;
You can do this using Hooks, useState to store data and useEffect to call API,
import React, {useState,useEffect} from "react";
import Head from './head';
function App(){
const [data, setData] = useState([])
useEffect(() => {
const proxy = 'http://cors-anywhere.herokuapp.com/';
const api = `${proxy}http://starlord.hackerearth.com/books`;
fetch(api).then(response => {
setData(response.json())
})
},[])
return(
<div>
{data.length>0 && data.map(book => <Head book={book} />)
</div>
);
}
And you Head component should be,
function Head(props){
return(
<div className="app">
<div className="heading">
<h1>BOOK_CAVE</h1>
<div className="heading_description">So many books...so
little time...</div>
</div>
<div className="author">{props.book.authors}</div>
<div className="id">{props.book.bookID}</div>
<div className="price">{props.book.price}</div>
</div>
);
}
The books array you fetch from the API should be stored in a state and you should render the app according to that state. The data fetching should happen when the component mounted, so you make the call on componentDidMount lifecycle method, and update the state when the data finished fetching. Also, the Head component recieves three props, but you pass only one.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
books: [],
fetching: true,
}
componentDidMount() {
const proxy = 'http://cors-anywhere.herokuapp.com/';
const api = `${proxy}http://starlord.hackerearth.com/books`;
fetch(api)
.then(response => response.json() )
.then(data => this.setState({books: data, fetching: false,}) );
}
render() {
if (this.state.fetching) {
return <div>Loading...</div>
}
const headArray = this.state.books.map(book => (
<Head
authors={book.authors}
bookID={book.bookID}
price={book.price}
/>
));
return(
<div>
{headArray}
</div>
);
}
}
You need to:
Enclose the fetch n a lifecycle method or a useEffect hook
Put the API's response in a state (which will cause a re-render)
Iterate over the state in the return statement, using map, not forEach
Example using hooks:
function App(){
const [apiData, setApiData] = useState([])
const [isLoading, setIsLoading] = useState(true)
useEffect(
() => {
const proxy = 'http://cors-anywhere.herokuapp.com/';
const api = `${proxy}http://starlord.hackerearth.com/books`;
fetch(api).then(response => {
setApiData(response.json())
setIsLoading(false)
})
},
[]
)
const authors = data.map((index) => index.authors).flat()
return(
<div>
{authors.map((author) => <Head author{author} />)
</div>
);
}

Categories

Resources