Infinity fetching loop - javascript

Once I am opening my DocumentViewer fetching does infinity loop and I cannot see why this is happening, could somebody maybe see where is the problem, Its something to do with state and props but i cannot figure out why, it would be amazing to know what is the problem and how to approach it
class GeneralDocPresenter extends React.Component {
state = {
metaInfoDocs: [],
docs: [],
loading: false
};
updateDoc = () => {
this.props.selectedDocsStore.clear();
this.props.selectedDocsStore.setViewDocId(0);
this.setState({ loading: true });
this.props
.fetchMetaDocs()
.then((r) => this.setState({ metaInfoDocs: r.data, loading: false }))
.catch((err) => {
this.setState({ loading: false });
errorWithMessage("Could not load documents");
});
this.props.eventManager.on("viewDoc", (doc) => {
this.loadDocuments(doc.id);
});
};
componentDidUpdate(prevProps, prevState, snapshot) {
this.updateDoc()
}
componentDidMount() {
this.updateDoc()
}
render() {
return <Translation>
{(t) => {
if (this.state.loading) {
return (
<div style={{display: 'flex', justifyContent: 'center'}}>
<Spin size={"medium"}/>
</div>
)
}
if (this.state.metaInfoDocs.length === 0) {
return (
<div style={{display: 'flex', justifyContent: 'center'}}>
<NoDocumentsAlert><div dangerouslySetInnerHTML={{__html: t('noDocuments')}}/></NoDocumentsAlert>
</div>
)
}
return (
<DocViewWrapper docs={this.state.docs}
metaInfoDocs={this.state.metaInfoDocs.map(doc => {
return {...doc, type: this.props.type}
})}
eventManager={this.props.eventManager}
settings={this.props.settings}
childComponents={this.props.childComponents}
/>
)
}}
</Translation>
}
loadDocuments(id) {
this.props.loadDocument(id).then(r => {
this.setState({
docs: r.data
})
});
}
}

Try replacing ComponentDidUpdate from
componentDidUpdate(prevProps, prevState, snapshot) {
this.updateDoc()
}
To
componentDidUpdate(prevProps, prevState, snapshot) {
if(this.props !== prevProps){
this.updateDoc()
}
}
You can be more specific to didUpdate what to check instead of checking complete props change.

Related

Sort data by title in React

how can i sort my data by title? This is my code:
And how can i call this 3 calls at the same time? I tried with "Promise All" but didn't work for me..
Thanks for help! ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import './Style.css';
class PostList extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
data: [],
items: []
};
}
componentDidMount() {
fetch(this.props.url)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
data: result.data,
items: result.items
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, data } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Please wait...</div>;
} else {
return (
<div> <table style={{ width: '100%'}}>
{data.items.map(item => (
<div>
<tr>
<th>Title:</th> <td>{item.title}</td>
</tr>
<tr>
<th>Artist:</th> <td>{item.artist}</td>
</tr>
<tr>
<th>Label:</th> <td>{item.label}</td>
</tr>
<tr>
<th>Year:</th> <td>{item.year}</td>
</tr>
</div>
))}
</table>
</div>
);
}
}
}
export default PostList
AND
import React, {Component} from 'react';
import PostList from './PostList';
class index extends Component {
render () {
return (
<div style={{
display: 'inline-flex'
}}>
<PostList url={"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list1"} />
<PostList url={"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list2"} />
<PostList url={"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list3"} />
</div>
)
}
}
export default index;
To sort the items just use Array.prototype.sort and String.prototype.localeCompare to compare the titles:
const sortedItems = data.items.sort((item1, item2) => item1.title.localeCompare(item2.title));
// and then render sorted items
{sortedItems.map(item => (...)}
If you want to do three calls at the same time you really need to use Promise.all. It can be done in parent component, or inside of PostList. So you can do the following:
const LIST_URLS = [
'https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list1',
'https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list2',
'https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list3'
];
...
async componentDidMount() {
this.setState({ isLoading: true });
try {
const lists = await Promise.all(LIST_URLS.map((url) => {
return fetch(this.props.url).then(res => res.json());
});
const list = lists.flat();
const sortedList = data.items.sort((item1, item2) => item1.title.localeCompare(item2.title));
this.setState({ list: sortedList });
} catch (error) {
this.setState({ error });
} finally {
this.setState({ isLoading: false });
}
}
render() {
// here you can just render single list with all the items, passing them as a prop
const { isLoading, error, items } = this.state;
return (
<div>
{isLoading && 'Loading...'}
{items && <PostList list={this.state.list} />}
{error && 'Failed to fetch'}
</div>
);
}
If all 3 API data should be sorted, then you have to use like below. If you want individual API responses to be sorted use sort before updating the state.
class PostList extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
data: [],
items: [],
};
this.callAPi = this.callAPi.bind(this);
}
callAPi(url) {
return fetch(url)
.then((res) => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
data: [...result.data].sort((item1, item2) =>
item1.title.localeCompare(item2.title)
),
items: [...result.items].sort((item1, item2) =>
item1.title.localeCompare(item2.title)
),
});
},
(error) => {
this.setState({
isLoaded: true,
error,
});
}
);
}
componentDidMount() {
Promise.all(props.urls.map(this.callAPi));
}
render() {
const { error, isLoaded, data } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Please wait...</div>;
} else {
return (
<div>
<table style={{ width: "100%" }}>
{data.items.map((item) => (
<div>
<tr>
<th>Title:</th> <td>{item.title}</td>
</tr>
<tr>
<th>Artist:</th> <td>{item.artist}</td>
</tr>
<tr>
<th>Label:</th> <td>{item.label}</td>
</tr>
<tr>
<th>Year:</th> <td>{item.year}</td>
</tr>
</div>
))}
</table>
</div>
);
}
}
}
USE
<PostList
urls={[
"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list1",
"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list2",
"https://api.netbet.com/development/randomFeed?website=casino&lang=eu&device=desktop&source=list3",
]}
/>;

Fetch is not happening once page refreshed

When i open a particular page, fetching is processing successfully and data received, however for some kind of reason, once page is refreshed the fetch is not even pending its not even visible in inspect. If something seems not right kindly point it out because I already spent ages trying to figure out why this is happening.
state = {
metaInfoDocs: [],
docs: [],
loading: false,
};
componentDidMount() {
this.props.selectedDocsStore.clear();
this.props.selectedDocsStore.setViewDocId(0);
this.setState({ loading: true });
this.props
.fetchMetaDocs()
.then((r) => this.setState({ metaInfoDocs: r.data, loading: false }))
.catch((err) => {
this.setState({ loading: false });
errorWithMessage("Could not load documents");
});
this.props.eventManager.on("viewDoc", (doc) => {
this.loadDocuments(doc.id);
});
}
export default class CentralDocuments extends React.Component {
render() {
return (
<GeneralDocPresenter
type={"centralInformationDocuments"}
fetchMetaDocs={() => getMetaInfoByType("central-document")}
loadDocument={(id) => getCentralDocuments(id)}
eventManager={new EventManager()}
childComponents={{
metaDocViewer: MetaInfoDocViewer,
metaView: MetaInfoListView,
}}
/>
);
}
}
You need to use componentDidUpdate() lifecycle method as well. For example:
updateDoc = () => {
this.props.selectedDocsStore.clear();
this.props.selectedDocsStore.setViewDocId(0);
this.setState({ loading: true });
this.props
.fetchMetaDocs()
.then((r) => this.setState({ metaInfoDocs: r.data, loading: false }))
.catch((err) => {
this.setState({ loading: false });
errorWithMessage("Could not load documents");
});
this.props.eventManager.on("viewDoc", (doc) => {
this.loadDocuments(doc.id);
});
}
componentDidUpdate() {
this.updateDoc()
}
componentDidMount() {
this.updateDoc()
}
You are only using componentDidMount(), you need to also put the code into componentDidUpdate().
Something like this ..
state = {
metaInfoDocs: [],
docs: [],
loading: false,
};
componentDidMount() {
this.props.selectedDocsStore.clear();
this.props.selectedDocsStore.setViewDocId(0);
this.setState({ loading: true });
this.props
.fetchMetaDocs()
.then((r) => this.setState({ metaInfoDocs: r.data, loading: false }))
.catch((err) => {
this.setState({ loading: false });
errorWithMessage("Could not load documents");
});
this.props.eventManager.on("viewDoc", (doc) => {
this.loadDocuments(doc.id);
});
}
componentDidUpdate() {
this.props.selectedDocsStore.clear();
this.props.selectedDocsStore.setViewDocId(0);
this.setState({ loading: true });
this.props
.fetchMetaDocs()
.then((r) => this.setState({ metaInfoDocs: r.data, loading: false }))
.catch((err) => {
this.setState({ loading: false });
errorWithMessage("Could not load documents");
});
this.props.eventManager.on("viewDoc", (doc) => {
this.loadDocuments(doc.id);
});
}
export default class CentralDocuments extends React.Component {
render() {
return (
<GeneralDocPresenter
type={"centralInformationDocuments"}
fetchMetaDocs={() => getMetaInfoByType("central-document")}
loadDocument={(id) => getCentralDocuments(id)}
eventManager={new EventManager()}
childComponents={{
metaDocViewer: MetaInfoDocViewer,
metaView: MetaInfoListView,
}}
/>
);
}
}
fixing the mistake

Can't perform a React state update

I have this kind of error:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
I have tried to follow some advice that I found but I haven't solved it. How can I do??
class Starting extends Component {
_isMounted = false
constructor(props) {
super(props);
this.state = {
loading: true,
};
}
componentDidMount() {
this._isMounted = true;
User.getUserLoggato()
.then(dataUserLoggato => {
if (dataUserLoggato !== null) {
global.user = new User(JSON.parse(dataUserLoggato));
Actions.homepage({ utente: global.user });
} else {
Actions.login();
}
})
.catch(err => {
console.log(err);
})
.finally(() => {
this.setState({ loading: false });
});
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
return (
<View style={style.container}>
<View style={style.page}>
<ActivityIndicator size="large" color="#56cbbe" />
</View>
</View>
);
}
}
Check if the component is mounted before you set the state:
.finally(() => {
this._isMounted && this.setState({ loading: false });
});

how do I make componentdidupdate not infinite loop or is there another way to update data?

I have an obstacle, that is if I press the cancel order button (batalkan pesanan) then an infinite loop appears, why do I use componentdidupdate because to update the new display or is there a better method besides componentdidupdate?
before pressing cancel order (batalkan pesanan
infinite loop occurs
the function is to update if after pressing the cancel order (batalkan pesanan) button the image below appears
this code :
import React, { Component } from "react";
import { Tabs, Spin } from "antd";
import { CustomTabPane } from "../../components/CustomTabDashboard";
import OrderListWaitingInDelivery from "../OrderListWaitingInDelivery";
import OrderListWaitingFinish from "../OrderListWaitingFinish";
import OrderListWaitingNotSent from "../OrderListWaitingNotSent";
import OrderListWaitingNotPay from "../OrderListWaitingNotPay";
import OrderDetailsDashboard from "../OrderDetailsDashboard";
import OrderDetailsCancel from "../OrderDetailsCancel";
import OrderListWaitingCancel from "../OrderListWaitingCancel";
import { apiGetWithToken } from "../../api/services";
import { PATH_DASHBOARD_TAB } from "../../api/path";
import NoOrderHistory from "../../components/NoOrderHistory";
const keyFnNames = {
'1': 'updateTabNotPay',
'2': 'updateTabNotSent',
'3': 'updateTabInDelivery',
'4': 'updateTabFinish',
'5': 'updateTabCancel'
};
class CustomerOderNavigation extends Component {
constructor(props) {
super(props);
this.state = {
isShowOrderDetailsDashboard: false,
orderId: null,
activeKey: "1",
loading: false,
productOrderNotYetPay: [],
productOrderNotYetSent: [],
productOrderInDelivery: [],
productOrderFinish: [],
productOrderCancel: []
};
}
componentDidMount(){
this.productOrderTabsNotYetPay();
}
componentDidUpdate() {
this.productOrderTabsNotYetPay();
//this.productOrderTabsNotYetSent();
// this.productOrderTabsInDelivery();
// this.productOrderTabsFinish();
// this.productOrderTabsCancel();
};
componentWillUnmount() {
this.setState({
loading: false
});
}
actionShowOrderListWaiting = () => {
this.setState({
isShowOrderDetailsDashboard: !this.state.isShowOrderDetailsDashboard
});
};
actionShowOrderDetailsDashboard = (orderId) => {
this.actionShowOrderListWaiting();
this.setState({
orderId: orderId
})
};
productOrderTabsNotYetPay = async () => {
try {
const response = await apiGetWithToken(PATH_DASHBOARD_TAB.ORDER_STATUS_NOT_YET_PAID);
const productOrderTabsNotYetPay = {
productOrderNotYetPay: response.data.data
};
this.setState({
...productOrderTabsNotYetPay,
loading: true
});
} catch (error) {
console.log(error);
this.setState({ loading: false });
}
};
productOrderTabsNotYetSent = async () => {
try {
const response = await apiGetWithToken(PATH_DASHBOARD_TAB.ORDER_STATUS_NOT_YET_SENT);
const productOrderTabsNotYetSent = {
productOrderNotYetSent: response.data.data,
loading: true
};
this.setState({
...productOrderTabsNotYetSent
});
} catch (error) {
console.log(error);
this.setState({ loading: false });
}
};
productOrderTabsInDelivery = async () => {
try {
const response = await apiGetWithToken(PATH_DASHBOARD_TAB.ORDER_STATUS_IN_DELIVERY);
const productOrderTabsInDelivery = {
productOrderInDelivery: response.data.data
};
this.setState({
...productOrderTabsInDelivery,
loading: true
});
} catch (error) {
console.log(error);
this.setState({ loading: false });
}
};
productOrderTabsFinish = async () => {
try {
const response = await apiGetWithToken(PATH_DASHBOARD_TAB.ORDER_STATUS_FINISH);
const productOrderTabsFinish = {
productOrderFinish: response.data.data
};
this.setState({
...productOrderTabsFinish,
loading: true
});
} catch (error) {
console.log(error);
this.setState({ loading: false });
}
};
productOrderTabsCancel = async () => {
try {
const response = await apiGetWithToken(PATH_DASHBOARD_TAB.ORDER_STATUS_CANCEL);
const productOrderTabsCancel = {
productOrderCancel: response.data.data
};
this.setState({
...productOrderTabsCancel,
loading: true
});
} catch (error) {
console.log(error);
this.setState({ loading: false });
}
};
updateTabNotPay = () => {
this.productOrderTabsNotYetPay();
};
updateTabNotSent = () => {
this.productOrderTabsNotYetSent();
};
updateTabInDelivery = () => {
this.productOrderTabsInDelivery();
};
updateTabFinish = () => {
this.productOrderTabsFinish();
};
updateTabCancel = () => {
this.productOrderTabsCancel();
};
handleChange = (selectedkey) => {
this.setState({ activeKey: selectedkey })
const fnName = keyFnNames[selectedkey];
if (fnName) {
this[fnName]();
}
};
render() {
return (
<Tabs activeKey={this.state.activeKey} onChange={this.handleChange} >
<CustomTabPane
key={"1"}
tab={
<span
onClick={() =>
this.setState({
isShowOrderDetailsDashboard: false
})}
>{"Belum Bayar"}</span>}
my_prop={
this.state.productOrderNotYetPay.length < 1 ?
(<Spin tip="Loading..." spinning={this.state.loading} delay={500}>
<NoOrderHistory />
</Spin>
) : (
this.state.isShowOrderDetailsDashboard === false ?
(<OrderListWaitingNotPay
productOrderNotYetPay={this.state.productOrderNotYetPay}
actionShowOrderDetailsDashboard={this.actionShowOrderDetailsDashboard}
tabsNotPay={1}
/>) : (
<OrderDetailsDashboard
orderId={this.state.orderId}
actionShowOrderListWaiting={() => this.actionShowOrderListWaiting()}
tabsNotPay={1}
/>)
)
}
/>
<CustomTabPane
key={"2"}
tab={<span
onClick={() =>
this.setState({
isShowOrderDetailsDashboard: false
})}>{"Sedang Diproses"}</span>}
my_prop={
this.state.productOrderNotYetSent.length < 1 ?
(<Spin tip="Loading..." spinning={this.state.loading} delay={500}>
<NoOrderHistory /></Spin>
) : (
this.state.isShowOrderDetailsDashboard === false ?
<OrderListWaitingNotSent
actionShowOrderDetailsDashboard={this.actionShowOrderDetailsDashboard}
productOrderNotYetSent={this.state.productOrderNotYetSent}
tabsNotSent={2}
/> : (
<OrderDetailsDashboard orderId={this.state.orderId}
actionShowOrderListWaiting={() => this.actionShowOrderListWaiting()}
tabsNotSent={2}
/>)
)
}
/>
<CustomTabPane
key={"3"}
tab={<span
onClick={() =>
this.setState({
isShowOrderDetailsDashboard: false
})}>
{"Dalam Pengiriman"}
</span>}
my_prop={
this.state.productOrderInDelivery.length < 1 ?
(<Spin tip="Loading..." spinning={this.state.loading} delay={500}>
<NoOrderHistory /></Spin>
) : (
this.state.isShowOrderDetailsDashboard === false ?
<OrderListWaitingInDelivery
productOrderInDelivery={this.state.productOrderInDelivery}
actionShowOrderDetailsDashboard={this.actionShowOrderDetailsDashboard}
tabsInDelivery={3}
/> : (
<OrderDetailsDashboard orderId={this.state.orderId}
actionShowOrderListWaiting={() => this.actionShowOrderListWaiting()}
tabsInDelivery={3}
/>)
)
} />
<CustomTabPane
key={"4"}
tab={<span
onClick={() =>
this.setState({
isShowOrderDetailsDashboard: false
})}>{"Selesai"}</span>}
my_prop={
this.state.productOrderFinish.length < 1 ?
(<Spin tip="Loading..." spinning={this.state.loading} delay={500}>
<NoOrderHistory /></Spin>
) : (
this.state.isShowOrderDetailsDashboard === false ?
<OrderListWaitingFinish
productOrderFinish={this.state.productOrderFinish}
actionShowOrderDetailsDashboard={this.actionShowOrderDetailsDashboard}
tabsFinish={4}
/> : (
<OrderDetailsDashboard orderId={this.state.orderId}
actionShowOrderListWaiting={() => this.actionShowOrderListWaiting()}
tabsFinish={4}
/>)
)
} />
<CustomTabPane
key={"5"}
tab={<span
onClick={() =>
this.setState({
isShowOrderDetailsDashboard: false
})}>{"Batal"}</span>}
my_prop={
this.state.productOrderCancel.length < 1 ?
(<Spin tip="Loading..." spinning={this.state.loading} delay={500}>
<NoOrderHistory /></Spin>
) : (
this.state.isShowOrderDetailsDashboard === false ?
<OrderListWaitingCancel
productOrderCancel={this.state.productOrderCancel}
actionShowOrderDetailsDashboard={this.actionShowOrderDetailsDashboard}
/> : (
<OrderDetailsCancel orderId={this.state.orderId}
actionShowOrderListWaiting={() => this.actionShowOrderListWaiting()}
/>)
)
}
/>
</Tabs>
);
}
}
export default CustomerOderNavigation;
You're running into an infinite loop because you're calling setState inside of the function you're calling in componentDidUpdate.
Calling setState in componentDidUpdate will always cause a re-render
To mitigate this, you should enclose the function you're calling inside a conditional expression.
componentDidUpdate(prevProps, prevState) {
// yourConditionalExpression can be any of the following:
// this.props.yourPropName !== prevProps.yourPropName
// this.state.yourStateVariable !== prevState.yourStateVariable
if (yourConditionalExpression) {
this.productOrderTabsNotYetPay();
}
}

After fetch state returns undefined

Im using fetch to post data to my local api, but when trying to get them and error like this occures. In fetch i get result perfectly fine, but after that trying to pass that into state like below:
this.setState({
items: result.items })
but items returns undefined and don't know why ?
My code:
class App extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
error: null,
isLoaded: false
};
this.setState = this.setState.bind(this);
}
componentDidMount() {
fetch("http://localhost:3000/items")
.then(res => res.json())
.then(result => {
console.log(result);
this.setState({
items: result.items,
isLoaded: true
});
console.log(this.state.items)
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul>
<h1>Saved items:</h1>
{
items && items.map(item => (
<li key={item.name}>
item: {item.name} {item.price}
</li>
))
}
</ul>
);
}
}
}
You can do either:
this.setState({
items: result.items || [],
isLoaded: true
});
or
{
items && items.map(item => (
<li key={item.name}>
{item.name} {item.price}
</li>
))
}

Categories