There are some environment variables in my .env file that gets updated when some values get updated on the database.
Example:
REACT_APP_FIREBASE_ID=1234567890
When I log this to the console on my react app:
console.log(process.env.REACT_APP_FIREBASE_ID) //this gives "1234567890"
But when the .env file is updated with something else:
Example:
REACT_APP_FIREBASE_ID=9876543210
The log still gives the old value:
console.log(process.env.REACT_APP_FIREBASE_ID) //this still gives "1234567890"
I am using on CRA on dev mode with "npm start"
If I terminate the server and restart it again, I am able to see the correct output to the console.
BUT, this doesn't work after "npm run build"
How can I clear the environment cache after the .env file is changed on the Production Mode?
This is how I solved it.
My first approach was to get the value from the .env file, but unless the server is restarted, this approach doesn't work. [BAD]
My second thought was to create a JSON file and keep the data from inside that, and update the JSON file whenever the Database is updated.
Sadly, this was a very bad approach because CRA (or probably any react project) cannot call a file outside the src folder and after the build, there is no scope to change the built js files. [VERY BAD]
Finally, I managed to solve this using this approach [DECENT, I Guess]
Saving the data on a table in a key-value format (You may just save in JSON format too)
When the application is loaded (main component is loaded), call an API that gets that key-value(or JSON) and store the data in the LocalStorage of the browser.
Get the value on the application with localStorage.getItem("theKeyName")
A Tip:
You could check if the key is already present on the LocalStorage before making the API call.
if(localStorage.getItem("theKeyName") !== null) {
//your API fetch request or redux dispatch
}
Related
I am trying to debug the getStaticProps() method of a React component included from my pages using console.log() like:
export default class Nav extends React.Component {
render() {
return <nav></nav>;
}
async getStaticProps() {
console.log('i like output, though');
}
}
However, I am neither able to see any output on the console from which the app is being served, nor on the browser's console. I also tried restarting yarn dev and running yarn build to see if it would produce output then. Alas, no cigar.
So what is the correct way to produce and read debug output from getStaticProps() and getStaticPaths()?
So after further research and testing I found out that getStaticProps() is only called on page components. So that was why I wasn't seeing any output. When I added the method to a component inside the pages directory I was able to see debug output produced with console.log() in the console running yarn dev on manual browser page refreshes (but not on automatic refreshes after modifying the page component) as well as during yarn build.
You can easily debug server-side code of your next application.
To enable it you need to pass NODE_OPTIONS='--inspect' to your node processor. Best place to put it is in your package.json file where you run the app in dev mode => "dev": "NODE_OPTIONS='--inspect' next dev" .
Now open a new tab in your chrome browser, and visit chrome://inspect. This will open chrome dev tool inspect where you can see your nextJs server under Remote Targets, Just click ìnspect. By clicking that it will open a new inspect window.
Now simply put debugger inside your getStaticProps function and reload your client app, you will see the breakpoint in your server side code.
I hope this helps.
Reference: https://nextjs.org/docs/advanced-features/debugging#server-side-code
getStaticProps runs on the server-side and not on the client-side.
getStaticProps only runs on the server-side. It will never run on the client-side. It won’t even be included in the JS bundle for the browser.
Ref: https://nextjs.org/learn/basics/data-fetching/getstaticprops-details
Using the current next version (11.x) you can use console.log to print out any data in the getStaticProps() function.
You will see that output in the terminal where you run
vercel dev
Your console.log will work but in the console of your app Terminal, not in the console in the browser. There you can check your message.
Also, if you get data [Object] then just in that console, make JSON.stringify(yourValue).
if it's a bigger object than stringify you can write like JSON.stringify(yourValue, null, 2) and it will be displayed within JSON way.
I am using CRA to setup my react app.
I want to ask, how do I make a locally accessed react app do API call.
To explain my question, I can only do it by describing it.
So currently, my machine has 192.168.1.2 as its IP.
My backend server is running on 192.168.1.2:3000 (if i hit 192.168.1.2:3000/customers on browser I get the json response)
My frontend is running on 192.168.1.2:3001
If i open http://localhost:3001 or http://192.168.1.2:3001 from my laptop browser, all components render, it will render the Loading component and then not long after the list will render. (If i check my backend server, i can see that my server receives GET request)
However if I open http://192.168.1.2:3001 from my phone, all components render, but it is stuck at Loading component. When I check my backend server, it receives no request at all. So from what I can see is that by accessing my react app locally outside from the hosting machine, the app won't do any API call.
How do I fix this?
Things I have done:
Adding "proxy": "http://localhost:3000" and "proxy": "192.168.1.2:3000" to package.json (both doesn't work)
Changing "start" script to: "HOST=0.0.0.0 react-scripts start" and "react-scripts start --host=0.0.0.0" (both does not work)
My best guess is that you are fetching from localhost similar to this:
fetch("http://localhost:3000/customers")
The reason proxy isn't working in the config file would be because you need to remove "http://localhost:3000" from the fetch. Otherwise, it is still pinging localhost for the api, and not using the proxy setting. So it should look like this:
fetch("/customers")
Of course, without a reproducible example, it is hard to tell if that is exactly the problem you are having.
I want to be able to pass a custom server hostname when running my React app to be used in the URL when I need to fetch data. The server is currently running on my local computer, so when I use fetch(<URL>).
I've been using "http://localhost:...." which has worked perfectly. But I want to be able to have to pass a custom host name, such as my IP address, to be used in the URL (i.e., http://ipaddress:...).
I've tried starting my app like this:
serverhost=ipaddress npm start
And then in my package.json file
"scripts" : {
"start": "react-scripts start $serverhost"
}
And in file start.js I can access process.env.serverhost, but I want to be able to access the hostname in the browser for my actual fetch calls. I don't want to set the hostname in "config" in package.json file or in an .env file, because it has to be able to change (I'm under the impression that this isn't possible). I just want to be able to access the server hostname given as an argument in the command line in my source files.
(I read somewhere about doing
REACT_APP_MY_VAR=test npm start
and then accessing it as
process.env.REACT_APP_MY_VAR
in the source files, but when I tried to fetch(<URL>), I got a bunch of failure to parse URL errors.)
I tried using REACT_APP variables and I no longer got parsing URL errors when fetching.
You can have .env file per environment and then set
REACT_APP_API_ENDPOINT=http://localhost.whatever
So for example .env.development
REACT_APP_API_ENDPOINT=http://localhost.whatever
.env.production
REACT_APP_API_ENDPOINT=http://production.whatever
Usage of env variables is explained here https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#what-other-env-files-can-be-used
Eventually, you can add it to your script like
"scripts" : {
"start": "REACT_APP_API_ENDPOINT=http://localhost.whatever npm/yarn start"
"start-production": "REACT_APP_API_ENDPOINT=http://production.whatever npm/yarn start"
}
If you don't really want to use above approaches at all then, assign your ip to some variable and add it to command to run your app
"scripts" : {
"start": "REACT_APP_API_ENDPOINT=$(curl ifconfig.me) npm/yarn start"
"start-other: "REACT_APP_API_ENDPOINT=$(echo MY_VAR_WITH_IP) npm/yarn start"
}
And then access your url from process.env.REACT_APP_API_ENDPOINT
You can set a base tag in your index.html that would set the base for all your requests from there on.
You can create the base tag dynamically by reading the document.location and map your required path.
Note that all relative paths will be then mapped from your baseTag
An example would be something like this
<base href="https://www.dog.ceo/" />
And then create a request like this
fetch('api/breeds/list/all')
.then( response => response.json() )
.then( ({message}) => console.log( message ) );
The full address of that call would the be https://www.dog.ceo/api/breeds/list/all
When I updated my site, run npm run build and upload the new files to the server I am still looking the old version of my site.
Without React, I can see the new version of my site with cache-busting. I do this:
Previous file
<link rel="stylesheet" href="/css/styles.css">
New file
<link rel="stylesheet" href="/css/styles.css?abcde">
How can I do something like this or to achieve cache busting with create react app?
There are many threads in the GitHub of create react app about this but no one has a proper/simple answer.
EDIT: create-react-app v2 now have the service worker disabled by default
This answer only apply for CRA v1
This is probably because of your web worker.
If you look into your index.js file you can see
registerServiceWorker();
Never wondered what it did? If we take a look at the file it got imported from we can see
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read {URL}
// This link also includes instructions on opting out of this behavior.
If you want to delete the web worker, don't just delete the line. Import unregister and call it in your file instead of the register.
import { unregister } from './registerServiceWorker';
and then call
unregister()
P.S. When you unregister, it will take at least one refresh to make it work
I had the same issue when I use create-react-app ( and deploy to heroku). It keeps showing the old version of my app 😡.
I found the problem seems to be on the browser side, it caches my old index.html with its outdated js bundle
You may want to add the following to your server side response header
"Cache-Control": "no-store, no-cache"
or if you are also using heroku create-react-app-buildpack, update the static.json file
"headers": {
"/**": {
"Cache-Control": "no-store, no-cache"
}
}
I think in this way you can still keep that poor service worker 😂, and the latest content will be shown on the N+1 load (second refresh)
Hope this helps...
As mentioned by some of the previous answers here, both the service worker and the (lack of) cache headers can conspire against you when it comes to seeing old versions of your React app.
The React docs state the following when it comes to caching:
Using Cache-Control: max-age=31536000 for your build/static
assets, and Cache-Control: no-cache for everything else is a safe
and effective starting point that ensures your user's browser will
always check for an updated index.html file, and will cache all of
the build/static files for one year. Note that you can use the one
year expiration on build/static safely because the file contents
hash is embedded into the filename.
As mentioned by #squarism, older versions of create-react-app defaulted to opt-out of service worker registration, while newer versions are opt-in. You can read more about that in the official docs. It's quite a straightforward process to match you configuration to the latest template if you started with an older version of create-react-app and you want to switch to the new behaviour.
Related questions:
How to avoid caching for create-react-app
ReactJS: How to prevent browser from caching static files?
how to clear browser cache in reactjs
If your problem is with resources statically referenced in index.html, such as .css files or additional .js files (e.g. configuration files), you can declare a React environment variable, assign a unique value to it and reference it in your index.html file.
In your build script (bash):
REACT_APP_CACHE_BUST={e.g. build number from a CI tool} npm run build
In your index.html:
<link rel="stylesheet" href="%PUBLIC_URL%/index.css?cachebust=%REACT_APP_CACHE_BUST%" />
The variable name has to start with REACT_APP_. More about environment variables in React: https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables.
It appears that they changed from opt-out to opt-in with regards to the service worker. Here's the commit that changed the README and it has examples similar to Kerry G's answer:
https://github.com/facebook/create-react-app/commit/1b2813144b3b0e731d8f404a8169e6fa5916dde4#diff-4e6ec56f74ee42069aac401a4fe448ad
Coming from a PHP background, I used to have an index.php which does two things:
serve the webpage if no parameters were set;
or serve JSON data when a specific POST parameter was included in the request.
Something like this:
// -- index.php
<?php
if ($_POST["some_parameter"]) {
...
echo json_encode(someArrayData);
exit(0);
}
?>
<html>
...
</html>
I have built the complete frontend application with npm, webpack, webpack-dev-server, and react. Having completed the first part, how can I effectively serve JSON data instead of HTML when a request includes a specific POST parameter?
I can see 2 ways of doing this:
Build the frontend as usual and everytime I build the bundle, modify index.html, inject my PHP code in it, and rename it to index.php. I then would have to run this folder via apache or nginx, so I'd be able to run the index.php script. This method is downright ugly and is probably the worst way to do it.
Run a separate PHP server which just serves data or redirects to the static webpack-generated build. All requests should then start from this server, and this server determines whether to serve data or redirect to the frontend. The problem comes to neatly passing the POST data received from the request to the static react app. As far as I know, the only way to do this would be to include a URL (GET) parameter to the redirect and manually parse it with javascript on the frontend. This is a dirty solution, in my opinion.
So, to summarize:
I need an efficient way to get POST data in a react/webpack/webpack-dev-server environment.
It should work with my hot-module-replacement dev setup.
I'm fine with switching to a node-based backend like express.
There shouldn't be any ajax involved in the static react app.
Any ideas? There has to be a way to do this properly.
UPDATE: I solved this by simply copying an index.php from my source directory to my build directory via the webpack config. I serve the build folder to a PHP server and keep a webpack --watch building my source.
I lose built-in features like auto-reload and css injection, but it's worth the convenience of not having to implement SSR for a very simple task (getting a single POST variable).
For anyone interested, I also added 2 npm scripts:
npm run start runs my original webpack-dev-server with hot-reload, serving static content including a static index.html file
npm run static runs the webpack --watch which copies the index.php file to the build directory
This lets me have hot-reloading when developing frontend, and allows POST data fetching when programming logic.
It's easy, convenient, and works on most web hosting providers.