How to make conditional import work in React JS? - javascript

I have three pages in my react website that have the same layout and different content. I've made an array within a js file to map through the content, but I don't want to duplicate my code to another component.
The point is the I need the variable name to be the same, so I can map it.
I can get what I need with require matching the page url, but since I read it's not a good practice in react due to performance issues, I'm trying to accomplish it with import with no sucess though.
let pagedata = [];
if (matchpage1) {
pagedata = require("./data").page1data;
} else if (matchpage2) {
pagedata = require("./data").page2data;
} else if (matchpage3) {
pagedata = require("./data").page3data;
}
return (
pagedata.map((item) => {
I've read the react documentation, searched a lot, tried a lot of code, but nothing works if I try a simiçar aproach with import and lazy.
let pagedata = [];
if (matchpage1) {
pagedata = React.lazy(() => import('./pagedata1'));
} else if (matchpage2) {
pagedata = React.lazy(() => import('./pagedata2'));
} else if (matchpage3) {
pagedata = React.lazy(() => import('./pagedata3'));
}
What am I doing wrong?
Thank you so much for your attention.

Related

Why sometimes useEffect does not work when I remove useless hooks inside/outside it?

This code was being used in my project which took the page to top whenever route changed and also when you click on a link of the same route you are on. I referred this answer to write the code below. The problem with the linked answer was that it didn't take the page to top if you click on a link which has the same route as you are on currently. So I modified it and wrote it like this.
import React, {useEffect} from 'react'
import { useLocation } from 'react-router-dom'
const Scroll2Top = () => {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
});
return null;
}
export default Scroll2Top
But when I remove the useLocation hook which is not even being used my code stops working. Why is this happening ?
Another similar example I came across is
// not being used but stops working if I remove this
let history = useNavigate();
useEffect(() => {
let termsInput = document.querySelector("#terms > input");
let claimInput = document.querySelector("#claim > input");
if (window.location.href.includes("#terms")) {
termsInput.checked = true;
claimInput.checked = false;
} else if(window.location.href.includes("#privacy")) {
termsInput.checked = false;
claimInput.checked = false;
}
else if (window.location.href.includes("#claim")) {
claimInput.checked = true;
termsInput.checked = false;
}
});
I have no clue why this happens and I was not able to find similar question anywhere on stackoverflow.
Its because you're not providing any dep array for useEffect it means it will run on every render of that component, and when you use useLocation hook it will be called everytime you move between pages which will cause rerender of that component, but if you remove that useLoaction hook there is no factor to cause rerender on that component so useEffect won't run.

Uncaught ReferenceError: Cannot access '__WEBPACK_DEFAULT_EXPORT__' before initialization

I have a problem with my webpack project, so I was trying to import one class to another and instantiate it but suddenly an error appear in my console and my program stopped working, it was this:
Uncaught ReferenceError: Cannot access '__WEBPACK_DEFAULT_EXPORT__' before initialization
This is the code of the class were I am trying to import my another class (that is PopUpPlugin):
import PopupPlugin from './popupPlugin.js';
export const addSearchBtnEvent = (weatherUI) => {
const searchBtn = document.querySelector('.weather__search');
searchBtn.addEventListener('click', () => {
weatherUI.style.opacity = '1';
weatherUI.style.visibility = 'visible';
})
}
export const addSearchExitEvent = (weatherUI) => {
const weatherExit = document.querySelector('.weather__search-exit');
weatherExit.addEventListener('click', () => {
weatherUI.style.opacity = '0';
weatherUI.style.visibility = 'hidden';
})
}
const popupObj = new PopupPlugin();
class searchDashboard {
constructor() {
}
setInputEvent() {
const inputSearch = document.querySelector('.weather__city-search');
const inputSearchBtn = document.querySelector('.weather__search-btn');
inputSearchBtn.addEventListener('click', () => {
const inputSearchVal = inputSearch.value;
this.validateStr(inputSearchVal);
});
}
validateStr() {
const onlyLettersAndSpaces = /^[a-zA-Z][a-zA-Z\s]*$/;
if(str.trim().length > 0 && str.match(onlyLettersAndSpaces)) {
const strValue = str.toLowerCase().trim().replace(' ', '+');
this.popupObj.searchCoincidences(strValue, 'weather__search-ui');
}
}
}
export default searchDashboard;
I don't actually know why this is happening, I also tried to instantiate it inside the constructor and it worked but it sended me the error of an stack overflow.
PD: If someone needs it here is the code of the PopupPlugin. (Here is what was working to me that was instantiating the class inside the constructor until the stack overflow error appeared)
import ManageWeatherDashboard from './manageWeatherDashboard.js';
import { getFetch, repeatAppend } from './weatherHelpers.js';
class popupPlugin {
constructor() {
this.manageWeatherDashboardObj = new ManageWeatherDashboard();
}
validateStr(str) {
const onlyLettersAndSpaces = /^[a-zA-Z][a-zA-Z\s]*$/;
if(str.trim().length > 0 && str.match(onlyLettersAndSpaces)) {
const strValue = str.toLowerCase().trim().replace(' ', '+');
return strValue;
}
}
searchCoincidences(val, parent) {
getFetch(`https://www.metaweather.com/api/location/search/?query=${val}`)
.then(res => res.text())
.then(data => {
const parentResults = document.querySelector('.'+parent);
parentResults.innerHTML = '';
const dataArr = JSON.parse(data)
if(dataArr.length >= 15) {
let resVal;
for(let i = 0; i <= 15; i++) {
resVal = this.addDOMResultCoincidences(parent, dataArr[i].title,
dataArr[i].woeid);
}
this.whenClickCoincidence(resVal);
} else {
let resVal;
dataArr.forEach(el => {
resVal = this.addDOMResultCoincidences(parent, el.title, el.woeid);
})
this.whenClickCoincidence(resVal);
}
})
}
addDOMResultCoincidences(parentBlock, name, id) {
const args = Array.from(arguments);
if(args[0] === 'popup__results') {
const popupResults = document.querySelector('.popup__results');
const divResult = document.createElement('div');
divResult.className = 'popup__result';
divResult.setAttribute('data-woeid', id);
const spanResultName = document.createElement('span');
spanResultName.className = 'popup__result-name';
const cityReturn = document.createTextNode(args[1]);
spanResultName.appendChild(cityReturn);
divResult.appendChild(spanResultName);
popupResults.prepend(divResult);
return divResult;
}
if(args[0] === 'weather__search-ui') {
const weatherUI = document.querySelector('.weather__search-ui');
const divResult = document.createElement('div');
divResult.className = 'weather__search-result';
divResult.setAttribute('data-woeid', id);
const spanResultName = document.createElement('span');
const spanResultNameText = document.createTextNode(args[1]);
spanResultName.className = 'weather__city-result';
spanResultName.appendChild(spanResultNameText);
const iconResult = document.createElement('i');
iconResult.className = 'fa fa-arrow-right weather__go-result';
repeatAppend([spanResultName, iconResult], divResult);
weatherUI.appendChild(divResult);
return divResult;
}
}
// When click a coincidence in search field
whenClickCoincidence(el) {
const woeId = el.getAttribute('data-woeid');
el.addEventListener('click', () => {
let handler = 0;
if(handler === 0) {
getFetch(`https://www.metaweather.com/api/location/${woeId}/`)
.then(res => res.json())
.then(data => {
const popup = document.querySelector('.popup');
const weatherNext6Days = data.consolidated_weather;
this.manageWeatherDashboardObj.changeWeatherBar(weatherNext6Days[0], data.title);
weatherNext6Days.slice(1, 6).forEach(el => {
this.manageWeatherDashboardObj.nextFiveDays(el);
})
this.manageWeatherDashboardObj.updateStadistics(weatherNext6Days[0]);
popup.style.opacity = '0';
popup.style.visibility = 'hidden';
})
}
handler += 1;
})
}
}
export default popupPlugin;
This might be caused by a cyclic dependencies (i.e. moduleA imports module B and vice versa at the same time). Take a deeper look at your code.
I faced the same issue when I moved the import statement for the redux store below some import of a local module that was dealing with some reducer reference from of the store. Moving the import store from ./store upwards resolved this issue for me.
Try fixing the order of imports in your files.
Had this problem, after upgrading from webpack 4 to webpack 5, and, yes, it was a circular dependency in my case.
Furthermore I found this blog How to Eliminate Circular Dependencies from Your JavaScript Project which led me to https://github.com/aackerman/circular-dependency-plugin
Plopped the plugin into my webpack dev config, as per sample on github, then spent some time reading its output figuring out where I went wrong. Fixing things was pretty easy once I knew the problem - it had been a pretty basic error.
circular-dependency-plugin#5.2.2 works on webpack 4 apparently, and I can confirm it works on webpack#5.73.0 as well. Saved me lots of time :-) You can take it out of webpack dev config after it's done its work.
In my case, it was due to circular import. Meaning, that two modules are exporting and importing contents form each other
For anyone whose issue is not a circular dependency, it could also be a missing import.
In my case, using Material UI 5, I forgot the line import { styled } from "#mui/styles";, which gave me this error:
Uncaught ReferenceError: Cannot access '__WEBPACK_DEFAULT_EXPORT__' before initialization
instead of the usual ReferenceError: MyModule is not defined missing import error.
Using my IDE auto import I had something like:
import useStore, { useCart } from "../lib/store"
Everything was working fine for awhile! But then I got the same error until I changed my import to be like this:
import { useStore, useCart } from "../lib/store"
in my case, I was just trying to call the dispatch function before the store had fully loaded - i.e. store.dispatch()
Have same issue in nextjs project.
Switching to previous versions or reinstalling node_modules/ - did not help.
Solution - remove build/ directory and restart build.
In my case, it was the entry-point file that used the following syntax:
export default <symbol>;
Maybe because you used circle import.
For me, I used encapsulated axios to request in mobx store, and I also used some data from mobx store in encapsulated axios.
This isn't exactly what's causing the same error to occur for me.
Mine were caused by calling things like useState, useEffect and firebase() outside the main functional Component Block. This is very dumb but I somehow completely missed it.
Hope it helps anyone from the future who had the same problem as mine.

React / ES6 - Efficiently update property of an object in an array

I am looking for the most efficient way to update a property of an object in an array using modern JavaScript. I am currently doing the following but it is way too slow so I'm looking for an approach that will speed things up. Also, to put this in context, this code is used in a Redux Saga in a react app and is called on every keystroke* a user makes when writing code in an editor.
*Ok not EVERY keystroke. I do have debounce and throttling implemented I just wanted to focus on the update but I appreciate everyone catching this :)
function* updateCode({ payload: { code, selectedFile } }) {
try {
const tempFiles = stateFiles.filter(file => file.id !== selectedFile.id);
const updatedFile = {
...selectedFile,
content: code,
};
const newFiles = [...tempFiles, updatedFile];
}
catch () {}
}
the above works but is too slow.
I have also tried using splice but I get Invariant Violation: A state mutation
const index = stateFiles.findIndex(file => file.id === selectedFile.id);
const newFiles = Array.from(stateFiles.splice(index, 1, { ...selectedFile, content: code }));
You can use Array.prototype.map in order to construct your new array:
const newFiles = stateFiles.map(file => {
if (file.id !== selectedFile.id) {
return file;
}
return {
...selectedFile,
content: code,
};
});
Also, please consider using debouncing in order not to run your code on every keystroke.

I am not able to save the quantity of my ordered items in the local storage with react and javascript

I'm a beginner javascript developer. I am trying to create a component for adding a product to the shopping cart with React, using local storage. I manage to register the id of my product by clicking on the button, but I cannot increment a quantity on a product ordered more than once.
This is my composant :
import React from 'react';
import {useParams} from 'react-router-dom';
function AddToBasket() {
const id = useParams().id;
let cartProduct = [];
let cartQty = [];
function handleClick(AddToBasket,e) {
if (localStorage.getItem('cartProduct') != null) {
console.log(localStorage.getItem('cartProduct'));
var localProduct = JSON.parse(localStorage.getItem('cartProduct'));
var localQty = JSON.parse(localStorage.getItem('cartQty'));
if (localProduct.indexOf(id)!== -1) {
var indexId = 0;
indexId = localProduct.indexOf(id);
console.log(indexId);
localProduct.forEach((indexId) => {
localProduct.push(id);
localQty++})
localStorage.setItem('cartProduct', JSON.stringify(localProduct));
localStorage.setItem('cartQty', JSON.stringify(localQty));
}
else {
localProduct.push(id);
localQty.push(1);
console.log(cartProduct);
localStorage.setItem('cartProduct', JSON.stringify(localProduct));
localStorage.setItem('cartQty', JSON.stringify(localQty));
}
}
else {
cartProduct.push(id);
cartQty.push(1);
console.log(cartProduct);
localStorage.setItem('cartProduct', JSON.stringify(cartProduct));
localStorage.setItem('cartQty', JSON.stringify(cartQty));
}
}
return (
<button onClick={handleClick}>Ajout au panier</button>
)
}
export default AddToBasket;
What is wrong with my code? Thanks in advance for your feedback
When the compiler reaches the else part after finding a particular ID, it always pushes 1 to the quantity. I don't see any increment done here. So the localQty is repeatedly being assigned with the value 1. Try to increment, the value. You are using plain JavaScript, there's no use of React here. If you're don't have a complete understanding of JS, please don't proceed with ReactJS as you might end up hating the library. Hope it helps!..

Variables Being Changed In Fetch But Unchanged Outside of Function

I have a React App and I have an App container where I want to call a fetch to get some data to pass through to components that will need that information.
I've declared variables outside of the an onload function (where my fetch is located) and assigned them different values in the fetch. They variables will change in the fetch but outside of the fetch they remain unchanged.
How come they are not staying changed and is there a way to fix this?
I've tried changed the variables declared with var instead of let and I've tried putting the function inside the const.
I've also tried putting the fetch inside of other components (like Table as seen below) but then I have to declare two states and call a fetch withint a fetch because I'm already calling another fetch there and it becomes cumbersome...
let latestRelease = 0;
let draftRelease = 0;
let doClone = false;
function onload() {
fetch(url, {
method: 'GET'
})
.then(function(response) {
return response.json();
})
.then(function(result) {
for(var i = 0; i < result.length; i++)
{
if(result[i].id > latestRelease && result[i].status === "released") {
latestRelease = result[i].id;
}
if(result[i].id > draftRelease && result[i].status === "draft") {
draftRelease = result[i].id;
}
}
if(latestRelease > draftRelease) {
doClone = true;
}
})
.catch((error) => {
console.log(error);
});
}
const App: React.FC = () => {
onload()
return (
<React.Fragment>
<CssBaseline />
<Container fixed>
<PersistentDrawerLeft/>
{console.log(latestRelease)} //displays 0
<Title/>
<Table />
</Container>
</React.Fragment>
);
}
export default App;
I'm expecting for latestRelease and draftRelease to not stay as 0 but anything greater than that but the output is just 0. With the correct values returned I'd then like to pass them as props to the components.
Many thanks!
Part of the issue is that you don't seem to be properly distinguishing between synchronous and asynchronous code. fetch is asynchronous, meaning that that code is not guaranteed to run before anything else in the file. (fetch uses JS promises to manage async data, so it helps to have a good grasp on using promises.)
In a typical React case, you want to do a few things differently. First, you want to use component state to hold on to the data, rather than just random variables (this allows React to re-render when those values change). Secondly, when you're fetching data asynchronously, you need to work out what your app should do before the fetch is complete.
Here's a very basic example showing how this could work:
import React, { useState, useEffect } from 'react'
const App = ({ url }) => {
// We'll use this variable to store an object with the details
const [releaseDetails, setReleaseDetails] = useState(null)
// When the component is loaded, we'll fetch the url (coming from the component props) and then
// run your logic.
useEffect(() => {
let latestRelease = 0;
let draftRelease = 0;
let doClone = false;
fetch(url)
.then((response) => response.json())
.then((result) => {
for(var i = 0; i < result.length; i++) {
if(result[i].id > latestRelease && result[i].status === "released") {
latestRelease = result[i].id;
}
if(result[i].id > draftRelease && result[i].status === "draft") {
draftRelease = result[i].id;
}
}
if(latestRelease > draftRelease) {
doClone = true;
}
// To make these details available to the component, we'll bundle them into an object
// and update the component's state:
setReleaseDetails({
latestRelease,
draftRelease,
doClone
})
})
.catch((error) => {
// You'd ideally want some proper error handling here
console.log(error)
});
}, []) // pass an empty array so this is only run when the component is first rendered
// Because we're getting the data asynchronously, we need to display something while we wait
if(releaseDetails === null) {
return "loading..."
}
// Once the data is available, you can then use the details when rendering. You could instead
// render a child component and pass the values as props to it.
return (
`LatestRelease: ${releaseDetails.latestRelease}`
)
}
Speaking generally, there are probably a few React and general JS concepts you'll want to make sure you have your around, particularly around state and async data fetching. Not sure how much experience you've had with it so far, but you may want to take a look at some intro tutorials (possibly like this official one) to see how much you can follow and if there's anything that jumps out as something you need to familiarise yourself with more.
can you please try with state variable ,because if state variable changes the render will call again, here your using a normal variable may be its changing but its not rendering.
Thank You.
Variable should be in the state for re rendering

Categories

Resources