GraphQL endCursor and React State - reactjs

I'm trying to implement a pagination on my react fe. I'm calling my data on page load and setting the endCursor for the pagination into a react hook variable.
However when I click 'load more' button on my page it goes and fetches new data and should upset the endCursor with the new value retrieved... but it only does this once and then stops working. I'm sure I'm doing something silly but I can't figure out what.
Here's the code..
const LatestDrops = () => {
const [newArrivals, setNewArrivals] = useState([])
const [offset, setOffset] = useState('')
// Run on page load
useEffect(() => {
listNewArrivals()
},[])
// Fetch new arrivals
const listNewArrivals = () => {
getNewArrivals()
.then(data => {
if (data.error){
console.log('Error fetching new arrivals', data.error)
} else {
setNewArrivals(data.edges)
setOffset(data.pageInfo.endCursor)
}
})
.catch(e => console.log('Failed to fetch', e))
}
// Fetch more arrivals on click
const handleLoadMore = (e) => {
console.log('Fetching more with offset: ', offset)
getMarketPlaceListings(offset)
.then((data) => {
if (data.error){
console.log('Error fetching marketplace listings', data.error)
} else {
setNewArrivals(data.edges)
console.log('Page offset from server is: ', data.pageInfo.endCursor)
setOffset(data.pageInfo.endCursor)
}
})
}
return(
<section>
Cursor: {JSON.stringify(offset)}
<button onClick={e => handleLoadMore()}>
View all
</button>
</section>
)
}
export default LatestDrops
I've also tried throwing in the old state when updating it as suggested by another post ie:
setOffset(offset => data.pageInfo.endCursor)

Related

React state not updated and error "Can't perform a React state update on an unmounted component"

I'm trying to create an app that once a user logs in (enters a partyID), it directs them to a new page where it pulls back all the users data. Once they 'Log In; the new page isn't pulling the data as I expected.
However when I write to console the data is says undefined but the fetch URL does work when i go to it locally on my browser.
enter image description here
Here is my code
class CalcForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
componentDidMount() {
this.setState({ isLoading: true });
const serachByCustomerId = this.props.location.state;
const url =
"<MYURL>/api/Customer/" +
serachByCustomerId;
console.log("URL Being used ", url);
fetch(url)
.then((res) => res.json())
.then((data) => this.setState({ data: data }))
if (!this.state.isLoading) {
console.log("data after search", this.state.data);
}
}
// renders to display on page
render() {
const { data, isLoading } = this.state;
// if page is loading displays loading text and spinner to make user awear
if (isLoading) {
return (
<div className="pageLoading">
<p>Loading...</p>
<FadeLoader size={150} color={"#2d8259"} loading={isLoading} />
</div>
);
}
return (
<div> hi </div>
);
}
}
export default CalcForm;
I was expected the data returned to be printed into the console but upon looking I get undefined and there is also an error I don't understand
setState is asynchronous, so if you want to console.log the data, it must be within a callback:
this.setState({key: value}, () => {console.log(value})
This is what your componentDidMount() would look like:
componentDidMount() {
this.setState({isLoading: true });
const searchByCustomerId = this.props.location.state;
const url = "<MYURL>/api/Customer/" + searchByCustomerId;
console.log("URL Being used ", url);
fetch(url)
.then((res) => res.json())
.then((data) => this.setState({data: data },
() => {
console.log("data after search", data);
this.setState({isLoading: false})
}
))
}
PLUS: you had a typo (search not serach)
Hope this helps :)
Why not go down the hooks approach? Its far more nicer and easier to do things:
psuedo code to get you going. It has an await function so you should be able to derive your data once you pass in your url.
export default function CalcForm() {
const [isLoading, setLoading] = React.useState(true);
const [data, setData] = React.useState(false);
const getData = async () => {
setLoading(true);
const response = await fetch(url);
setData(response.json());
setLoading(false);
};
React.useEffect(() => {
getData();
}, []);
if (isLoading) {
return (
<div className="pageLoading">
<p>Loading...</p>
<FadeLoader size={150} color="#2d8259" loading={isLoading} />
</div>
);
}
return <div className="pageLoading">hi</div>;
}

Fetching an array of objects from POKEAPI using REACT.js and AXIOS {Answered}

I chose to start learning API handling with POKEAPI. I am at a step where I need to get the flavor_text of each pokemon (the description let's say) but I can't for some reason.
Here is the JSON structure for one specific pokemon: https://pokeapi.co/api/v2/pokemon-species/bulbasaur.
And here is my useEffect trying to get it. The line fetching the habitat works and displays on my website so I guess my issue comes from my map in setDescription but I can't be sure.
export default function Card({ pokemon }, { key }) {
const src = url + `${pokemon.id}` + ".png";
const [habitat, setHabitat] = useState(null);
const [descriptions, setDescriptions] = useState([]);
useEffect(() => {
const controller = new AbortController();
axios
.get(url2 + `${pokemon.name}`, { signal: controller.signal })
.then((res) => setHabitat(res.data.habitat.name))
.then((res) =>
setDescriptions(
res.data.flavor_text_entries.map((ob) => ob.flavor_text)
)
)
.catch((err) => {
if (axios.isCancel(err)) {
} else {
console.log("warning your useEffect is behaving");
}
});
return () => {
// cancel the request before component unmounts
controller.abort();
};
}, [pokemon]);
I tried console logging descriptions or descriptions[0] but that doesn't work.
Since you only setting up the state from those data and it doesn't looks like the second result need to wait the result from the first to perform you can do both on the same response/promise :
useEffect(() => {
const controller = new AbortController();
axios
.get(url2 + `${pokemon.name}`, { signal: controller.signal })
.then((res) => {
setHabitat(res.data.habitat.name))
const flavorTextEntrieList = res.data.flavor_text_entries;
setDescriptions(flavorTextEntrieList.map((ob) => ob.flavor_text))
})
.catch((err) => {
if (axios.isCancel(err)) {
} else {
console.log("warning your useEffect is behaving");
}
});
return () => {
// cancel the request before component unmounts
controller.abort();
};
}, [pokemon]);
Each then need to return something to be handled in next chainable then. Replace .then((res) => setHabitat(res.data.habitat.name)) with .then((res) => { setHabitat(res.data.habitat.name); return res; })

why is my page reloading when re rendering a component

I am doing a api call and then another for each of the object received in the first request.
I have a load more button at the end of my page to get more data added on the page.
Each time the button is clicked the data is fetched but the page reloads and then makes the UI go back to the top of the page instead of just appending the new data.
Not sure what would force the page to reload?
This is my useEffect hook:
useEffect(() => {
//this if/else statement is to find out if the page has been reloaded
if (performance.navigation.type === 1) {
console.log("This page is reloaded");
} else {
console.log("This page is not reloaded");
}
setLoading(true);
let cancel;
axios
.get(currentPageUrl, {
cancelToken: new axios.CancelToken((c) => (cancel = c)),
}).then((res) => {
setLoading(false);
setNextpageUrl(res.data.next);
setPokemons([...pokemons, ...res.data.results])
}).catch((e) => {
setErr(true)
})
}, [currentPageUrl]);
this is the function that would change the currentPageUrl :
const handleClick = () => {
setCurrentPageUrl(nextPageUrl);
}
After a lot of trial and error, the solution was simply to create a function that would handle the logic then put it inside the use effect.
const request = () => {
if (performance.navigation.type === 1) {
console.log("This page is reloaded");
} else {
console.log("This page is not reloaded");
}
setLoading(true);
let cancel;
axios
.get(currentPageUrl, {
cancelToken: new axios.CancelToken((c) => (cancel = c)),
}).then((res) => {
setLoading(false);
setNextpageUrl(res.data.next);
setPokemons([...pokemons, ...res.data.results])
}).catch((e) => {
setErr(true)
})
}
useEffect(() => {
request()
}, [currentPageUrl])

can't access state hook from useEffect to other function on first render

I have two component (listProduct and detailProduct).
if I click one product on listProduct it's linking to detailProduct.
On detailProduct I using component name BtnBtm, and send props qtyItem from component detailProduct.
on my detailProduct component I using code as follow:
useEffect(() => {
let productId = props.match.params.id;
let productAct = productAPI.detailProduct(productId);
setOpenBD(true);
productAct.then((response) => {
setDetProduct(response.data);
setDetSatuan(response.data.detail_satuan);
setTimeout(() => {
setOpenBD(false);
}, 3000);
}).catch(error => {
setTimeout(() => {
setOpenBD(false);
}, 3000);
console.log(error)
});
fetchData();
},[]);
const fetchData = async () => {
let app_id = localStorage.getItem('sessionId');
if (app_id === null) {
localStorage.setItem('sessionId', lib.makeSessionId(40))
} else {
let getItemAct = cartAPI.getItems(app_id);
console.log(detProduct);
getItemAct.then((response) => {
const adf = response.data.find(o => o.product_id === detProduct._id);
if (adf !== undefined){
console.log('halo')
setQtyItem(adf.qty);
}
}).catch(error => {
console.log(error)
});
}
}
return (
<>
<Content />
<BtnBtm
qtyItem={qtyItem}
/>
</>
)
At first link from list to detail it's not update 'qtyItem',
but if I refresh the page (position now on detailProduct) it's updated qtyItem.
if You see 'console.log(detProduct);', it's return empty (first render from linking) and if I refresh it's return the data and updated qtyItem.
How i can updated on first render (from linking) to updated qtyItem, so component BtnBtm can update real data ???
Thanks for your help :)
Oke i found just updated like this
useEffect(() => {
let productId = props.match.params.id;
let productAct = productAPI.detailProduct(productId);
setOpenBD(true);
productAct.then((response) => {
setDetProduct(response.data);
fetchData(response.data);
setDetSatuan(response.data.detail_satuan);
setTimeout(() => {
setOpenBD(false);
}, 3000);
}).catch(error => {
setTimeout(() => {
setOpenBD(false);
}, 3000);
console.log(error)
});
},[]);

React Native - state is returning null after setting state

I'm very much new to react native currently i'm building small app for just getting an idea about this. I'm facing an issue in mapping the data from API. This is the json response returning from the api
{"data":[{"digit":300,"countsum":"52"},{"digit":301,"countsum":"102"},{"digit":302,"countsum":"27"},{"digit":303,"countsum":"201"},{"digit":500,"countsum":"101"}]}
When i tried to map this data i'm facing some issues. I stored the response from API to the state and when i tried to display the state data using map function it's showing the state value is null. This the code i tried till now
const [listdata, setListData] = useState(null)
useEffect(() => {
// Run! Like go get some data from an API.
getListData();
}, []);
const getListData = async () => {
const token = await AsyncStorage.getItem("#userToken")
axios
.get(constants.BASE_URL + "getlist?token=" +token)
.then(response => setListData(response.data))
.catch(error => {
console.log(error);
});
listdata.map(item => <Text>{item.digit}</Text>)
}
Do it like this,
export default function ComponentName () {
const [listdata, setListData] = useState([])
useEffect(() => {
// Run! Like go get some data from an API.
getListData();
}, []);
const getListData = async () => {
const token = await AsyncStorage.getItem("#userToken")
axios
.get(constants.BASE_URL + "getlist?token=" +token)
.then(response => setListData(response.data))
.catch(error => {
console.log(error);
});
}
return (<>
listdata.map(item => <Text>{item.digit}</Text>)
</>
);
}
You have to wait the fetch execution and later do the list map.
// wait for it
await axios
.get(constants.BASE_URL + "getlist?token=" +token)
.then(response => setListData(response.data))
.catch(error => {
console.log(error);
});
listdata.map(item => <Text>{item.digit}</Text>)
If you want to map the data then do that inside return statement of your code ,like:
return(
{listData?listdata.map(item => return <Text>{item.digit}</Text>):""}
);
This is a sample of a meant in my comment above:
Try console.log listdata at this stage, you will find that it is still
null, in other words, the value of the updated value of the
listdata:useSate will be ready after the render take place. You can
make another function outside of the current one. then use useEffect
with listdata to update your text views
const [listdata, setListData] = useState(null)
useEffect(() => makeRemoteRequest(), [listdata])
makeRemoteRequest = () => {
const url = `your-url-of-data-here`;
fetch(url)
.then(res => res.json())
.then(res => {
setListData(res.data);
})
.catch(error => {
console.log(error)
});
};
You could try the following:
const [listdata, setListData] = useState([])
useEffect(() => {
// Run! Like go get some data from an API.
getListData();
}, []);
const getListData = async () => {
const token = await AsyncStorage.getItem("#userToken")
try {
const dataResponse = await axios.get(constants.BASE_URL + "getlist?token=" +token);
setListData(dataResponse.data || [] );
} catch(error) {
console.log(error);
}
}
return (<>
listdata.map(item => <Text>{item.digit}</Text>)
</>);

Resources