Nextjs _app.js shared layout how to run server side ( Closed ) - reactjs

I have a simple nextjs application
=> pages/_app.js
function MyApp({ Component, pageProps }) {
return <Provider store={store}><SiteLayout><Component {...pageProps} /></SiteLayout></Provider>
}
=> layouts/SiteLayout.js : In here, I make a request to api and draw the menu.
export default function SiteLayout({ children }) {
const dispath = useDispatch()
useEffect(() => {
fetch("testlink", {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
method: 'POST',
body: "client=web"
})
.then(response => response.json())
.then(data => dispath(addFeed(data)))
}, [])
return (
<>
<Menu />
{children}
</>
)
}
I know it is not server-side rendered and my problem is that I want to do it server-side because the menu tree can’t show in the source code. I need to request one time and draw a scaffold of the application in SiteLayout shared component. Did anyone solve or face that?
MyApp.getInitialProps = async function (context) {
const data = await fetch("testlik", {
headers: { "Content-Type": "application/x-www-form-urlencoded" },
method: 'POST',
body: "client=web"
}).then(response => response.json())
return {
pageProps:{
menu: data?.data?.menu ?? null
}
}
}
getInitialProps is fixed my issue

Related

React - API call running multiple times

I'm writing a react app that fetches data from two different APIs. In the code below, I call the two APIs then console.log the response. After npm start, in the console, I see that the response has been console.logged a few times. I don't know why it's doing this and it's causing issue with the app's behavior. It's receiving the data from aws dynamoDB tables.
function App() {
const [ response , setResponse ] = useState();
const [ btnText , setbtnText ] = useState('Get Data');
const [ details , setDetails ] = useState();
async function fetchData() {
try {
await fetch('url hidden' , {
method: 'POST',
header: {'Content-Type': 'application/json'},
}).then(res => res.json())
.then(res => setResponse(res))
await fetch('url hidden' , {
method: 'POST',
header: {'Content-Type': 'application/json'},
}).then(res => res.json())
.then(res => setDetails(res))
} catch (error) {
console.log(error);
};
}
console.log(response)
return (
<div className="container">
<header className='header'>
<button onClick={fetchData}>{btnText}</button>
</header>
<Summary response={response} details={details} />
</div>
);
}
I also tried useEffect to fetch data as soon as app loads, but it's doing the same thing.
useEffect(() => {
try {
Promise.all([
fetch('url hidden' , {
method: 'POST',
header: {'Content-Type': 'application/json'},
}).then(res => res.json()).then(res => setResponse(res)),
fetch('url hidden' , {
method: 'POST',
header: {'Content-Type': 'application/json'},
}).then(res => res.json()).then(res => setDetails(res)),
]);
}
catch(err) {
console.log(err);
}
} , [])
this image shows the response after clicking the button only once
When you use console.log in the the functional component you will get that console.log each time the component rerenders. And that happens for example each time you set a new state.
You could just move the console.log inside the fetch function.
Or you just console.log the values in useEffect if they change. Like in the example below.
I also refactored the fetchData function to use async await and Promise.all more efficient.
Also you were missing an "s" for "headers" for the fetch method.
async function fetchData() {
try {
const [response, details] = await Promise.all([
(
await fetch("url hidden", {
method: "POST",
headers: { "Content-Type": "application/json" },
})
).json(),
(
await fetch("url hidden", {
method: "POST",
headers: { "Content-Type": "application/json" },
})
).json(),
]);
setResponse(response);
setDetails(details);
} catch (error) {
console.log(error);
}
}
useEffect(() => {
fetchData();
}, []);
useEffect(() => {
console.log(response, details);
}, [response, details]);
If you move console.log(response) inside fetchData then you will get exact information about how many times handler executes, and it really should be only once, on click.
With your approach you moved log in component body and this will cause log to execute each time element rerenders - probably 3 times: one log initially when element is loaded in DOM, and other 2 when you set states inside handler.

Return of Child Component within useEffect and Fetch not working

I'm facing a weird problem. The next code returns correctly inside its useEffect and fetch functions... Nevertheless, the child component is not being rendered. I think it might be because of the map(), but i'm not even sure about it.
Any ideas? Thanks in advance.
const FilesComponent = () => {
let result = useRef({
files: [],
folders: []
});
useEffect(() => {
console.log('useEffect...');
fetch('http://192.168.1.36:3001/api/files/', {
method: 'GET',
headers: {
'Content-Type': 'application/json; charset=',
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYmxhY2tvdXQiLCJlbWFpbCI6ImJsYWNrb3V0QGRvbWFpbi5jb20iLCJpYXQiOjE2NDkxMjk4OTMsImV4cCI6MTY0OTIxNjI5MywiaXNzIjoiY2xvdWRsaXRlLXR5cGVzY3JpcHQifQ.i6ik5YTxahBWwKVJdWJUw6dR4vAkwM4ytc-3eSBSzoQ'
},
credentials: 'include'
})
.then(response => response.json())
.then(data => {
dispatch({type: 'ChangeMessage',
files: data.data.files,
folders: data.data.folders
});
const action = {
type: 'ChangeMessage'
};
result.current = reducer({}, action);
console.log(result.current);
return (
<React.Fragment>
<ul className="files-list">
{
result.current.files.map(file => <File href={'https://www.google.com/'} key={file.name} value={file}/>)
}
{
result.current.folders.map(folder => <File href={'https://www.google.com/'} key={folder.name} value={folder}/>)
}
</ul>
</React.Fragment>
);
});
}, [result]);
return (
<>
</>
);
};

I see the requested value in my console, but not on my page

I'm kind of stuck at the moment. I see my value in my console, but I don't see it on my page. I am not sure how to fix it. I am new to this and not sure if it has something to do with with GET/POST method?
import "./styles.css";
import * as React from "react";
export default function Hi() {
const matic = useMatic();
return (
<div>
<h1>{matic}</h1>
</div>
);
}
function useMatic() {
const [matic, setMatic] = React.useState([]);
React.useEffect(() => {
fetch(
"https://api.coingecko.com/api/v3/simple/price?ids=matic-network&vs_currencies=usd",
{
method: "GET",
headers: {
"cache-control": "max-age=30,public,must-revalidate,s-maxage=60",
"Content-Type": "application/json; charset=utf-8"
}
}
)
.then((response) => response.text())
.then((response) => setMatic(response))
.catch((error) => console.log("error", error));
}, []);
return matic;
}

React renders component many times when fetching data

I'm using fetch api so my goal is to fire a POST request and then store the result received from this call in a state. This is the code that I use:
interface IPreviewFile {
file: IFile;
}
export default function PreviewFileModal({ file }: IPreviewFile) {
const source = useSelector((state: AppState) => state.source);
const project = useSelector((state: AppState) => state.project);
const data = {
fileName: file.path,
accountName: source.Name,
bucket: source.bucket,
id: source.id
};
useEffect(() => {
Promise.all([
fetch(`${API_URL}/api/project/${project.id}/filepreview`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
])
.then(async ([aa]) => {
const a = await aa.json();
return [a];
})
.then((responseText) => {
setStringArray(readString(responseText[0].value).data);
})
.catch((err) => {
console.log(err);
});
}, [project.id, data]);
console.log(stringArray);
return (
<>
<div></div>
</>
);
}
The console.log(stringArray); prints in the console all the time after delay of 2-3 seconds. As you can see, I use Promise in order to avoid this but for some reason it still happens. Any ideas what causes the re-rendering all the time and how to fix it?
I've tried changing the code a bit to avoid re-rendering the component due to the data variable added as a dependency to useEffect. I don't see any reference to stringArray, so i've added it as a state variable.
export default function PreviewFileModal({ file }: IPreviewFile) {
const source = useSelector((state: AppState) => state.source);
const project = useSelector((state: AppState) => state.project);
const [stringArray, setStringArray] = useState("");
useEffect(() => {
fetch(`${API_URL}/api/project/${project.id}/filepreview`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
fileName: file.path,
accountName: source.Name,
bucket: source.bucket,
id: source.id
})
})
.then(res => res.json())
.then((result) => {
result && setStringArray(readString(result.value).data);
})
.catch((err) => {
console.log(err);
});
}, [project.id]);
console.log(stringArray);
return (
<>
<div></div>
</>
);
}

React Native refresh content when user hits back button - using Hooks

I would like to refresh the data, when user is back from one page to another.
This is how my useEffect function looks like now:
useEffect(() => {
setIsLoading(true);
AsyncStorage.getItem("user").then((response) => {
const currentData = JSON.parse(response);
setUser(currentData)
fetch('URL',
{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
user_id: currentData.id
}),
}
)
.then(response => response.json())
.then(data => {
setNotis(data.notifications);
setIsLoading(false)
})
.catch(error => {
});
});
}, []);
This function should run every time when user is on the page. Doesn't matter if it was onBackPressed or not.
Thanks
Using React-navigation
We can directly refresh screen if you're using react-navigation
Import #react-navigation/native
import React, { useEffect } from "react";
import { useIsFocused } from "#react-navigation/native";
const HomeScreen = (props) => {
const isVisible = useIsFocused();
useEffect(() => {
console.log("called when screen open and also on close");
// this will call on both screen open and screen close.
if (isVisible) {
console.log("called when screen open or when back on screen ");
}
}, [isVisible]);
return (
......
)
}
I hope it will help.
The real problem here is that the screen is not being unmounted when navigating outside of it, so the hook won't fire since the component is already mounted. There are multiple options to solve this issue just as adding a listener when the screen gets focused/blurred or just watch for the changes for the navigation prop. For the last workaround, you could try something like:
useEffect(() => {
setIsLoading(true);
AsyncStorage.getItem("user").then((response) => {
const currentData = JSON.parse(response);
setUser(currentData)
fetch('URL',
{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
user_id: currentData.id
}),
}
)
.then(response => response.json())
.then(data => {
setNotis(data.notifications);
setIsLoading(false)
})
.catch(error => {
});
});
}, [navigation]);
For watching onFocus event, you could import NavigationEvents from react-navigation and move the logic for the hook inside a function refreshData
import {NavigationEvents} from 'react-navigation`
...
<NavigationEvents onWillFocus={refreshData}/>
Also, you should be setting the isLoading state to false whenever the Promise has settle, for instance you could use
.finally(() => {
setIsLoading(false)
})

Resources