I am using vercel to deploy but I cannot figure out how to set up environmental variables, so I want to try method using fetch("/data.json"). I also have custom hook for fetching data.
But this does not work and I don't even see data on my local.
data.json file is directly inside /public folder. Can someone help me?
useFetch.js
import { useState, useEffect } from "react";
export const useFetch = (url, method = "GET") => {
const [data, setData] = useState(null);
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState(null);
const [options, setOptions] = useState(null);
const postData = (postData) => {
setOptions({
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(postData),
});
};
useEffect(() => {
const controller = new AbortController();
const fetchData = async (fetchOptions) => {
setIsPending(true);
try {
const res = await fetch(url, {
...fetchOptions,
signal: controller.signal,
});
if (!res.ok) {
throw new Error(res.statusText);
}
const json = await res.json();
setIsPending(false);
setData(json);
setError(null);
} catch (err) {
if (err.name === "AbortError") {
console.log("the fetch was aborted");
} else {
setIsPending(false);
setError("Could not fetch the data");
}
}
};
if (method === "GET") {
fetchData();
}
if (method === "POST" && options) {
fetchData(options);
}
return () => {
controller.abort();
};
}, [url, options, method]);
return { data, isPending, error, postData };
};
TaskList.js
import { useFetch } from "../hooks/useFetch";
import { useFrequency } from "../hooks/useFrequency";
//images
import Dot from "../assets/icon-ellipsis.svg";
// styles
import "./TaskList.scss";
export default function TaskList() {
// const [url, setUrl] = useState("http://localhost:3000/stats");
const { data: stats, isPending, error } = useFetch("/data.json");
const { frequency } = useFrequency();
const urlDot = "#";
return (
<div className="main__inner">
{isPending && <div>Loading stats...</div>}
{error && <div>{error}</div>}
<ul className="main__task-list">
{stats &&
stats.map((stat) => (
<li
className={
stat.title === "Self Care"
? "main__task-item selfcare"
: `main__task-item ${stat.title.toLowerCase()}`
}
key={stat.id}
>
<div className="main__task-item-container">
<h3 className="main__task-title">{stat.title}</h3>
<a href={urlDot} className="main__task-dot">
<img src={Dot} alt="more details" />
</a>
<span className="main__task-current">
{/* {frequency === "daily"
? stat.timeframes.daily.current
: frequency === "weekly"
? stat.timeframes.weekly.current
: stat.timeframes.monthly.current}
hrs */}
{stat.timeframes[frequency].current}hrs
</span>
<span className="main__task-previous">
{frequency === "daily"
? "Yesterday"
: frequency === "weekly"
? "Last Week"
: "Last Month"}{" "}
-{" "}
{
/* {frequency === "daily"
? stat.timeframes.daily.previous
: frequency === "weekly"
? stat.timeframes.weekly.previous
: stat.timeframes.monthly.previous} */
stat.timeframes[frequency].previous
}
hrs
</span>
</div>
</li>
))}
</ul>
</div>
);
}
You can configure the Environment variable in Vercel after you have imported your site from GitHub or another repository.
You can set it on the Configure Project window by clicking the Environment Variable Tab. See the image below
Related
When I use map function for the following code, after deleting an user, I get an error: map is not a function.
import React, { useEffect } from 'react';
import useAxiosFunction from "../../hooks/useAxiosFunction";
import axios from 'axios'
const UsersList = () => {
const [users, error, loading, axiosFetch] = useAxiosFunction();
const getData = () => {
axiosFetch({
axiosInstance: axios,
method: 'get',
url: 'http://localhost:3500/users'
});
}
useEffect(() => {
getData();
// eslint-disable-next-line
}, [])
const handleDelete = (id) => {
axiosFetch({
axiosInstance: axios,
method: 'delete',
url: 'http://localhost:3500/users',
requestConfig: {
data: {
id: id
}
}
});
}
const content = (
<div>
<h1> USERS LIST </h1>
{loading && <p>Loading...</p>}
{!loading && error && <p className="errMsg">{error}</p>}
{!loading && !error && users?.length &&
<ul>
{ users.map((user, i) => (<li key={user._id}>{`${user.username}`}<button onClick={() => handleDelete(user._id)}>BUTTON</button></li>)) }
</ul>
}
{!loading && !error && !users?.length && users?.data &&
<p>{`userId: ${users.data?.userId}, title: ${users.data?.title}, body: ${users.data?.body}`}</p>}
{!loading && !error && !users && <p>No users to display</p>}
</div>
)
return content
}
export default UsersList
my useAxiosFunction.js
import { useState, useEffect } from "react";
const useAxiosFunction = () => {
const [response, setResponse] = useState([]);
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const [controller, setController] = useState();
const axiosFetch = async (configObj) => {
const {
axiosInstance,
method,
url,
requestConfig = {}
} = configObj;
try {
setLoading(true);
const ctrl = new AbortController();
setController(ctrl);
const res = await axiosInstance[method.toLowerCase()](url, {
...requestConfig,
signal: ctrl.signal
});
console.log(res);
setResponse(res.data);
} catch (err) {
console.log(err.message);
setError(err.message);
} finally {
setLoading(false);
}
}
useEffect(() => {
console.log(controller)
// useEffect cleanup function
return () => controller && controller.abort();
}, [controller]);
return [response, error, loading, axiosFetch];
}
export default useAxiosFunction
I've added:
{ Array.isArray(users) && users?.map((user, i) => (<li key={user._id}>{${user.username}}<button onClick={() => handleDelete(user._id)}>BUTTON</button></li>)) }
to check if users is array and it's not rendering until getData() is called again.
I can't understand why it map function works after refresh but not after deleting an user.
I'm trying to make a sport/tinder like app for a school project from a friend of mine. It came together well on my localhost, but for him it was a requirement to host it online. Not really a professional in hosting, but I was a bit familiar with Heroku. I used a client and a server side for my application, so I build the client side and put it into the server side folder. This server side is hosted on the Heroku page. But whenever I try to login, it won't work and I get this error message in my console.
TypeError: Cannot read properties of undefined (reading 'map')
The error says it is caused by this line of code.
const matchedUserIds = matches.map(({user_id}) => user_id)
This is the whole MatchDisplay file that is used in my Dashboard. I'm using a MongoDB for the storage of my users.
import axios from "axios";
import { useEffect, useState } from "react";
import { useCookies } from "react-cookie";
const MatchesDisplay = ({ matches, setClickedUser }) => {
const [matchedProfiles, setMatchedProfiles] = useState(null);
const [cookies, setCookie, removeCookie] = useCookies(null);
const [matched, setMatched] = useState(null);
const matchedUserIds = matches.map(({ user_id }) => user_id);
const userId = cookies.UserId;
const getMatches = async () => {
try {
const response = await axios.get(
"https://[app].herokuapp.com/users",
{
params: { userIds: JSON.stringify(matched()) },
}
);
setMatchedProfiles(response.data);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getMatches();
}, [matches]);
const filteredMatchedProfiles = matchedProfiles?.filter(
(matchedProfile) =>
matchedProfile.matches.filter(
(profile) => profile.user_id === userId
).length > 0
);
return (
<div className="matches-display">
{filteredMatchedProfiles?.map((match) => (
<div
key={match.user_id}
className="match-card"
onClick={() => setClickedUser(match)}
>
<div className="img-container">
<img
src={match?.url}
alt={match?.first_name + "profile"}
/>
</div>
<h3>{match?.first_name}</h3>
</div>
))}
</div>
);
};
export default MatchesDisplay;
Any help is welcome. If you need more code examples, please reply ;)
EDIT
The ChatContainer that passes the user to the MatchesDisplay.
import ChatHeader from "./ChatHeader";
import MatchesDisplay from "./MatchesDisplay";
import ChatDisplay from "./ChatDisplay";
import { useState } from 'react';
const ChatContainer = ({user}) => {
const [ clickedUser, setClickedUser] = useState(null)
return (
<div className="chat-container">
<ChatHeader user={user}/>
<div>
<button className="option" onClick={() => setClickedUser(null)}>Matches</button>
<button className="option" disabled={!clickedUser}>Chat</button>
<button className="option" >Prices</button>
</div>
{!clickedUser && <MatchesDisplay matches={user.matches} setClickedUser={setClickedUser}/>}
{clickedUser && <ChatDisplay user={user} clickedUser={clickedUser}/>}
</div>
)
}
export default ChatContainer
The Dashboard that passes the user to the Chatcontainer.
import TinderCard from 'react-tinder-card';
import {useEffect, useState} from 'react';
import {useCookies} from 'react-cookie';
import ChatContainer from '../components/ChatContainer'
import axios from "axios";
const Dashboard = () => {
const [user, setUser] = useState(null)
const [genderedUsers, setGenderedUsers] = useState(null)
const [lastDirection, setLastDirection] = useState(null)
const [cookies, setCookie, removeCookie] = useCookies(['user'])
const [matchedUserIds, setMatchedUserIds] = useState(null)
const [filteredGenderedUsers, setFilteredGenderedUsers] = useState(null)
const userId = cookies.UserId
const getUser = async () => {
try {
const response = await axios.get('https://funfit-webpage.herokuapp.com/user', {
params: {userId}
})
return setUser(response.data)
} catch (error) {
console.log(error)
}
}
const getGenderedUsers = async () => {
try {
const response = await axios.get('https://funfit-webpage.herokuapp.com/gendered-users', {
params: {gender: user?.gender_interest}
})
return setGenderedUsers(response.data)
} catch (error) {
console.log(error)
}
}
useEffect(() => {
getUser()
}, [])
useEffect(() => {
setMatchedUserIds(user?.matches.map(({user_id}) => user_id).concat(userId))
if (user) return getGenderedUsers()
}, [user])
useEffect(() => {
if (genderedUsers) {
return setFilteredGenderedUsers(genderedUsers?.filter(
genderedUser => !matchedUserIds.includes(genderedUser.user_id)
))
}
}, [genderedUsers])
const updateMatches = async (matchedUserId) => {
try {
await axios.put('https://funfit-webpage.herokuapp.com/addmatch', {
userId,
matchedUserId
})
return getUser()
} catch (error) {
console.log(error)
}
}
const swiped = (direction, swipedUserId) => {
console.log(direction, swipedUserId)
if (direction === 'right') {
updateMatches(swipedUserId)
}
return setLastDirection(direction)
}
const outOfFrame = (name) => {
console.log(name + ' left the screen!')
}
return (<>
{user && <div className="dashboard">
<ChatContainer user={user}/>
<div className="swipe-container">
<div className="card-container">
{filteredGenderedUsers?.map((genderedUser) =>
<TinderCard
className='swipe'
key={genderedUser.user_id}
onSwipe={(dir) => swiped(dir, genderedUser.user_id)}
onCardLeftScreen={() => outOfFrame(genderedUser.first_name)}>
<div style={{backgroundImage: 'url(' + genderedUser.url + ')'}} className='card'>
<h3>{'Name: ' + genderedUser.first_name} <br/> {'Sport: ' + genderedUser.about}</h3>
</div>
</TinderCard>)}
<div className="swipe-info">
{lastDirection ? <p>You swiped {lastDirection}</p> : <p/>}
</div>
</div>
</div>
</div>}
</>)
}
export default Dashboard
I have outsourced a fetch function into lib/cityData.js
const fetch = require('cross-fetch');
const dev = process.env.NODE_ENV !== 'production';
const server = dev ? 'http://localhost:3000' : 'https://your_deployment.server.com';
const fetchCityData = (city) => {
const options = {
method: `POST`,
};
fetch(`${server}/api/weather?city=${city}`, options)
.then((response) => {
if(response.ok){
return response.json().then(data => console.log(data))
}
throw new Error('Api is not available')
})
.catch(error => {
console.error('Error fetching data in city data: ', error)
})
}
//fetchCityData('London')
module.exports.fetchCityData = fetchCityData;
Data is an object, so fetchCityData('London') returns
{
location: {
name: 'London',
region: 'City of London, Greater London',
country: 'United Kingdom',
lat: 51.52,
lon: -0.11,
tz_id: 'Europe/London',
localtime_epoch: 1632394483,
localtime: '2021-09-23 11:54'
},
current: {
last_updated_epoch: 1632393900,
last_updated: '2021-09-23 11:45',
temp_c: 18,
temp_f: 64.4,
is_day: 1,
condition: {
text: 'Partly cloudy',
icon: '//cdn.weatherapi.com/weather/64x64/day/116.png',
code: 1003
},
wind_mph: 13.6,
wind_kph: 22,
wind_degree: 250,
wind_dir: 'WSW',
pressure_mb: 1020,
pressure_in: 30.12,
precip_mm: 0,
precip_in: 0,
humidity: 73,
cloud: 75,
feelslike_c: 18,
feelslike_f: 64.4,
vis_km: 10,
vis_miles: 6,
uv: 4,
gust_mph: 11.2,
gust_kph: 18
}
}
So, now I have a component and this needs this data. The process is as follows
In input user types city
Auto select gets fired
onSelect city is set (setCity(city))
This happens in the component SearchBar.js. Then city is being passed to the component ForecastButtons.js
This component takes the city and then onClick it should call my function above fetchCityData.js and return current temperature for the selected city. Before my fetchCityData function was part of ForecastButtons component, but I needed to outsource it, so now, of course the code is broken:
import React, { useState } from 'react';
import fetchCityData from '../lib/cityData'
export const ForecastButtons = ({ city }) => {
const [payload, setPayload] = useState(null)
const [error, setError] = useState(null)
const [loading, setLoading] = useState(true)
const location = payload?.location?.name;
const currentTemp = payload?.current?.temp_c;
return(
<div className="sm:col-span-2">
<p className="block text-sm font-medium text-gray-700">Select forecast</p>
<button onClick={fetchCityData} className="mt-1 bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded" type='button'>
Today
</button>
<p key={city?.location?.id} className='my-5'>
{ location ? `Current weather in ${location} is ${currentTemp} degrees ` : 'Please search for city to see current weather'}
</p>
</div>
)
}
setPayload in this component was called after fetch returned json. Now the payload is basically my data. Should I import the function somehow and setPayload(data)? I am new to react, this is way to complex for me. How do I use fetchCityData, setPayload and onClick in the button of my component still get the weather?
So I did just quick sketch how it could be. As I sad I transformed fetchCityData to hook usefetchCityData which return [data, loading, error]. We call that hook providing city. Inside hook when city changing useEffect calls server, updates all states, and returns [data, loading, error]. I am using my fake data and timeout to imitate network connection, also you can get fake error from server.
hooks.js:
// import axios from "axios";
import React from "react";
const useFetchCityData = (city) => {
const [data, setData] = React.useState();
const [loading, setLoading] = React.useState(false);
const [error, setError] = React.useState(false);
React.useEffect(() => {
const dev = process.env.NODE_ENV !== "production";
const server = dev
? "http://localhost:3000"
: "https://your_deployment.server.com";
setData(undefined);
setLoading(true);
setError(false);
const options = {
method: `POST`,
};
// axios(`${server}/api/weather?city=${city}`, options)
new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.2) {
resolve(`data from server for ${city}`);
}
reject();
}, 2000);
})
.then((data) => {
setData(data);
setLoading(false);
})
.catch((error) => {
console.error("Error fetching data in city data: ", error);
setLoading(false);
setError(true);
});
}, [city]);
return [data, loading, error];
};
export { useFetchCityData };
App.js:
import React from "react";
import { useFetchCityData } from "./hooks";
const App = () => {
const [city, setCity] = React.useState("London");
const [data, loading, error] = useFetchCityData(city);
return (
<div>
<div>data: {data}</div>
<div>loading: {loading.toString()}</div>
<div>error: {error.toString()}</div>
</div>
);
};
export default App;
Another solution would simply be:
cityData.js
const fetch = require('cross-fetch');
const dev = process.env.NODE_ENV !== 'production';
const server = dev ? 'http://localhost:3000' : 'https://your_deployment.server.com';
const fetchCityData = (city) => {
const options = {
method: `POST`,
};
return fetch(`${server}/api/weather?city=${city}`, options)
.then((response) => {
if(response.ok){
return response.json()
}
throw new Error('Api is not available')
})
.catch(error => {
console.error('Error fetching data in city data: ', error)
})
}
ForecasButtons.js
import React, { useState, useEffect } from 'react';
import { fetchCityData } from '../lib/cityData'
export const ForecastButtons = ({ city }) => {
const [payload, setPayload] = useState(null)
const getData = () => {
fetchCityData(city).then((payload) => setPayload(payload));
}
const location = payload?.location?.name;
const currentTemp = payload?.current?.temp_c;
return(
<div className="sm:col-span-2">
<p className="block text-sm font-medium text-gray-700">Select forecast</p>
<button onClick={getData} className="mt-1 bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded" type='button'>
Today
</button>
<p key={city?.location?.id} className='my-5'>
{ location ? `Current weather in ${location} is ${currentTemp} degrees ` : 'Please search for city to see current weather'}
</p>
</div>
)
}
It works, but as a beginner, I can't tell if this solution has any downsides.
I'm building a website using React Hooks and I've got two different pages (Workshops.js and Shows.js) fetching data from the same API, just with different parameters (?type=0 and ?type=1).
Once the data is fetched I'm mapping the results (It would be nice to have a reusable component there..see the comments in the code below). When the user click either on a show or a workshop he will be redirected to the same page.
Now singularly the code works.
Is there a more elegant way to avoid repeating the same code? ...something like Services in Angular?
Thank you!
Here is Workshop.js.
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom'
import api from '../../maps/Api'
const Workshops = () => {
const [ workshops, setWorkshop ] = useState([])
const [ isLoading, setIsLoading ] = useState(false)
const [ error, setError ] = useState(null)
const GET_URL = api.get.workshops /* http://someapi/workshops?type=0 */
useEffect(() => {
setIsLoading(true)
fetch(GET_URL, {headers: {
"Accept": "application/json",
"Access-Control-Allow-Origin": "*"
}})
.then(res => {
return (res.ok) ? res.json() : new Error("Mistake!")
})
.then(workshops => {
if(workshops.upcoming) {
setWorkshop(workshops.upcoming);
}
setIsLoading(false);
})
.catch(error => {
setError(error)
})
}, [GET_URL])
if ( error ){ return <p>{ error.message }</p> }
if ( isLoading ){
return <p>Loading workshops...</p>
}
return(
<main>
<div className='content'>
<div className='contentCol'>
<ul id='workshopBox'>
{
workshops.map( (workshop, i) => (
<li> // FROM HERE...
<div
className='workshop-active'>
<h2>{ workshop.title }</h2>
<p>{ workshop.description }</p>
<p>{ workshop.place }</p>
<p>{ (new Date(workshop.date).toLocaleDateString("it-IT", {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
}))}</p>
<p>{ (new Date(workshop.date).toLocaleTimeString("it-IT", {
hour: '2-digit',
minute: '2-digit',
hour12: true
}))}</p>
<p> Full price { workshop.price_full + ', 00'} € </p>
<p> Early bird price { workshop.price_earlybirds + ', 00'} € </p>
<p>
<Link to={`/workshops/${ workshop.id}`}>
<button>Details</button>
</Link>
</p>
<br/>
</div>
</li> //..to HERE I WOULD LIKE TO USE A REUSABLE COMPONENT
))
}
</ul>
</div>
</div>
</main>
)
}
export default Workshops
and here's Shows.js
import React, { useState, useEffect } from 'react';
//import { Link } from 'react-router-dom'
import api from '../maps/Api'
const Spettacoli = () => {
const [ shows, setShows ] = useState([])
const [ isLoading, setIsLoading ] = useState(false)
const [ error, setError ] = useState(null)
const GET_URL = api.get.shows /* http://someapi/workshops?type=1 */
useEffect(() => {
setIsLoading(true)
fetch(GET_URL, {headers: {
"Accept": "application/json",
"Access-Control-Allow-Origin": "*"
}})
.then(res => {
return (res.ok) ? res.json() : new Error("Mistake!")
})
.then(shows => {
setShows(shows)
setIsLoading(false)
})
.catch(error => {
setError(error)
})
}, [GET_URL])
return(
<main>
<div className='content'>
<div className='contentCol'>
/* SAME INTERFACE AS WORKSHOP */
</div>
</div>
</main>
)
}
export default Shows
So you may create your custom hook:
function useMyDataFetch(GET_URL) {
const [ data, setData ] = useState([])
const [ isLoading, setIsLoading ] = useState(true)
const [ error, setError ] = useState(null)
useEffect(() => {
let hasBeenAborted = false; // added
setIsLoading(true)
fetch(GET_URL, {headers: {
"Accept": "application/json",
"Access-Control-Allow-Origin": "*"
}})
.then(res => {
return (res.ok) ? res.json() : new Error("Mistake!")
})
.then(data => {
if (hasBeenAborted) return; // added
if(data.upcoming) {
setData(data.upcoming);
}
setIsLoading(false);
})
.catch(error => {
if (hasBeenAborted) return; // added
setIsLoading(false); // added
setError(error)
});
return () => { hasBeenAborted = true; } // added
}, [GET_URL]);
return { data, error, isLoading };
}
and use that in your components.
Notice lines I've marked with // added.
hasBeenAborted allows us react in case GET_URL has been updated for any reason for the same component. Cleanup in useEffect is really important so we avoid race conditions.
Instead of hasBeenAborted flag we could use AbortController but with that we would still fall into catch branch and need additional if to distinguish if request has been cancelled or actually failed. So just matter of taste to me.
As for your components they will use hook like that:
const Workshops = () => {
const {isLoading, error, data: workshops} = useMyDataFetch(api.get.workshops);
if ( error ){ return <p>{ error.message }</p> }
if ( isLoading ){
return <p>Loading workshops...</p>
}
return(
// the same here
);
}
export default Workshops
I try to do Load More on a list of data as written below:
import React, { useState, useEffect } from "react";
import { render } from "react-dom";
import axios from "axios";
import "./style.css";
const App = () => {
const LIMIT = 2;
const [data, setData] = useState([]);
const [isLoading, setLoading] = useState(false);
const [page, setPage] = useState(1);
const loadData = async (skip = 1, limit = LIMIT) => {
const URL = "https://reqres.in/api/users";
const headers = {
"Content-Type": "application/json",
Accept: "application/json"
};
const params = {
page: skip,
per_page: limit
};
const a = await axios.get(URL, { params, headers });
// const b = [...new Set([...data, ...a.data.data])]; <-- setting this will thrown error
setData(a.data.data);
setLoading(false);
};
useEffect(() => {
setLoading(true);
loadData(page);
}, [page]);
useEffect(() => {
console.log("page", page, "data", data.length);
}, [page, data]);
const doReset = evt => {
evt.preventDefault();
setPage(1);
};
const doLoadMore = evt => {
evt.preventDefault();
setPage(page + 1);
};
return (
<div className="container">
<h1>Listing</h1>
<button className="btn text-primary" onClick={evt => doReset(evt)}>
Reset
</button>
<button className="btn text-primary" onClick={evt => doLoadMore(evt)}>
Load More
</button>
{isLoading && <p>Loading..</p>}
{!isLoading && (
<ul>
{data.map(a => (
<li key={a.id}>
{a.id}. {a.email}
</li>
))}
</ul>
)}
</div>
);
};
render(<App />, document.getElementById("root"));
a fully working example in here.
i think this code should be working, but is not.
const a = await axios.get(URL, { params, headers });
const b = [...new Set([...data, ...a.data.data])];
setData(b);
so please help, how to do Load More in React Hooks?
after a few try, i think this is the best thing i can do. make the code working but also not let the compiler warning:
import React, { useState, useEffect, useCallback } from "react";
import axios from "axios";
import Navbar from "./Navbar";
const App = () => {
const LIMIT = 2;
const [tube, setTube] = useState([]);
const [data, setData] = useState([]);
const [isLoading, setLoading] = useState(false);
const [page, setPage] = useState(1);
const loadData = useCallback(
async (limit = LIMIT) => {
setLoading(true);
const URL = "https://reqres.in/api/users";
const headers = {
"Content-Type": "application/json",
Accept: "application/json"
};
const params = {
page,
per_page: limit
};
const a = await axios.get(URL, { params, headers });
if (!a.data.data) {
return;
}
setData(a.data.data);
setLoading(false);
},
[page]
);
useEffect(() => {
if (!isLoading) {
return;
}
setTube([...new Set([...tube, ...data])]);
}, [data, isLoading, tube]);
useEffect(() => {
loadData();
}, [loadData]);
useEffect(() => {
console.log("page", page, "data", data.length);
}, [page, data]);
const doLoadMore = evt => {
evt.preventDefault();
setPage(page + 1);
};
return (
<>
<Navbar />
<main role="main" className="container">
<div className="starter-template text-left">
<h1>Listing</h1>
<button className="btn text-primary" onClick={evt => doLoadMore(evt)}>
Load More
</button>
<ul>
{tube &&
tube.map(a => (
<li key={a.id}>
{a.id}. {a.email}
</li>
))}
</ul>
{isLoading && <p>Loading..</p>}
</div>
</main>
</>
);
};
export default App;
also i found, it could be much easier just apply this eslint-disable-next-line react-hooks/exhaustive-deps to let the compiler ignore the warning. something like this.
useEffect(() => {
setConfig({...config, params: {...params, skip}});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [skip]);
for information can be found on this:
how-to-fix-missing-dependency-warning-when-using-useeffect-react-hook
https://stackoverflow.com/a/55844055/492593
react #14920
I got your example to work by changing to this:
const b = [...data, ...a.data.data];
setData(b);