I am using leaflet, javascript, and react. The leaflet has a plugin called Leaflet sync.
This plugin sync two or more map demo. I want to synchronize the map in two different browsers' tabs. Leaflet sync does not work in two different tabs. Here is my code so far Code Link.
import React, { useEffect } from "react";
import L, { LatLngTuple } from "leaflet";
import { FC, useState } from "react";
import { MapContainer } from "react-leaflet";
import "./styles.css";
// import "leaflet.sync";
import MapContent from "./MapContent";
import styled from "styled-components";
import { Link, HashRouter as Router, Routes, Route } from "react-router-dom";
import MapOne from "./MapOne";
import MapTwo from "./MapTwo";
export default function App() {
const [center] = useState<LatLngTuple>([0, 0]);
const [bounds] = useState([
[432205, 6475078],
[437720, 6481113]
]);
const [zoom] = useState(0);
const [loaded, setLoaded] = useState(false);
const [mapA, setMapA] = useState<any>();
const [mapB, setMapB] = useState<any>();
return (
<Router>
<div style={{ display: "flex", flexDirection: "column" }}>
<Link to="/mapone" target="_blank">
Open Map One
</Link>
<Link to="/maptwo" target="_blank">
Open Map Two
</Link>
</div>
<Routes>
<Route exact path="/mapone" element={<MapOne />} />
<Route exact path="/maptwo" element={<MapTwo />} />
</Routes>
</Router>
);
}
// MapOne.tsx
export default function MapOne() {
const [center] = useState<LatLngTuple>([0, 0]);
const [bounds] = useState([
[432205, 6475078],
[437720, 6481113]
]);
const [zoom] = useState(0);
const [loaded, setLoaded] = useState(false);
const [mapA, setMapA] = useState<any>();
const [mapB, setMapB] = useState<any>();
useEffect(() => {
if (mapA) {
mapA.fitBounds(bounds);
}
// This does not work since mapB exist in another tab
// if (mapA && mapB) {
// mapA.sync(mapB);
// mapB.sync(mapA);
// mapA.fitBounds(bounds);
// }
}, [mapA, mapB, bounds]);
return (
<StyledDiv>
<h1>Map One</h1>
<MapContainer
whenReady={() => setLoaded(true)}
whenCreated={setMapA}
center={center}
zoom={zoom}
scrollWheelZoom={true}
placeholder={<MapPlaceholder />}
crs={L.CRS.Simple}
minZoom={-4}
>
<MapContent loaded={loaded} bounds={bounds} />
</MapContainer>
</StyledDiv>
);
}
// MapTwo.tsx
export default function MapTwo() {
const [center] = useState<LatLngTuple>([0, 0]);
const [bounds] = useState([
[432205, 6475078],
[437720, 6481113]
]);
const [zoom] = useState(0);
const [loaded, setLoaded] = useState(false);
const [mapA, setMapA] = useState<any>();
const [mapB, setMapB] = useState<any>();
useEffect(() => {
if (mapB) {
mapB.fitBounds(bounds);
}
// if (mapA && mapB) {
// mapA.sync(mapB);
// mapB.sync(mapA);
// mapA.fitBounds(bounds);
// }
}, [mapA, mapB, bounds]);
return (
<StyledDiv>
<h1>Map Two</h1>
<MapContainer
whenReady={() => setLoaded(true)}
whenCreated={setMapB}
center={center}
zoom={zoom}
scrollWheelZoom={true}
placeholder={<MapPlaceholder />}
crs={L.CRS.Simple}
minZoom={-4}
>
<MapContent loaded={loaded} bounds={bounds} />
</MapContainer>
</StyledDiv>
);
}
How can I use mapA.sync(mapB) to sync maps in two different browsers' tabs. I think I cannot since both are isolated from each other.
How can I achieve the same functionality as in leaflet sync but with different browser tabs?
Related
I am building an image search app using Unsplash API and trying to implement react infinite scroll (https://www.npmjs.com/package/react-infinite-scroll-component), but it is not working properly.
Now, the search form works fine and it displays 10 images(which is the default number of images using Unsplash API) when you search something, but when I scroll down to the end of of the page, it only displays the loader (h4 'Loading') but it does not display more images.
App.js
import './App.css';
import Main from './components/Main';
function App() {
return (
<div className="App">
<Main />
</div>
);
}
export default App;
Main.js
import React from 'react'
import Header from './Header'
import Image from './Image'
import { useState, useEffect } from 'react'
import InfiniteScroll from 'react-infinite-scroll-component';
function Main() {
const [input, setInput] = useState('')
const [allImages, setAllImages] = useState([])
const [favorites, setFavorites] = useState(() => JSON.parse(localStorage.getItem("favorites")) || [])
useEffect(() => {
localStorage.setItem("favorites", JSON.stringify(favorites))
console.log(favorites)
}, [favorites])
function handleChange(event) {
setInput(event.target.value)
}
async function fetchImages() {
try {
const res = await fetch(`https://api.unsplash.com/search/photos?&query=${input}&client_id=${process.env.REACT_APP_UNSPLASH_API_KEY}`)
const data = await res.json();
setAllImages(data.results)
} catch(error) {
alert("Sum ting wong");
}
}
const handleSubmit = async (event) => {
event.preventDefault();
fetchImages()
}
console.log(`allImages: ${allImages.length}`);
// use parameter 'id' to read specific one
function isLiked(id) {
return favorites.find(el => el.id === id) ? true : false
}
return (
<main>
<Header
input={input}
handleChange={handleChange}
handleSubmit={handleSubmit}
/>
<InfiniteScroll
dataLength={allImages.length} //This is important field to render the next data
next={fetchImages}
hasMore={true}
loader={<h4>Loading...</h4>}
>
<div className='main--image-list mt-5 pb-5'>
{allImages.map(el => (
<Image
key={el.id}
// do need spread operator below for img's src to work in Image.js
{...el}
el={el}
isLiked={isLiked(el.id)}
favorites={favorites}
setFavorites={setFavorites}
/>
))}
</div>
</InfiniteScroll>
</main>
)
}
export default Main
for visuals
I have been trying to set a search filter form. I am getting data from API (an array of cake objects with "id", "cake_name", "category" etc properties), these get displayed properly. But somehow my search function is not working? It should allow the user to input a name of a cake which then would be filtered through the cakes available and only the searched one(s) would be displayed.
I am getting this error:
error
Here is my code:
context.js:
import React, { useState, useContext, useEffect } from "react";
import { useCallback } from "react";
const url = "https://cakeaddicts-api.herokuapp.com/cakes";
const AppContext = React.createContext();
const AppProvider = ({ children }) => {
const [loading, setLoading] = useState(false);
const [searchTerm, setSearchTerm] = useState("");
const [cakes, setCakes] = useState([]);
const [filteredData, setFilteredData] = useState([]);
const fetchCakes = async () => {
setLoading(true);
try {
const response = await fetch(url);
const cakes = await response.json();
if (cakes) {
const newCakes = cakes.map((cake) => {
const {
id,
image,
cake_name,
category,
type,
ingredients,
instructions,
} = cake;
return {
id,
image,
cake_name,
category,
type,
ingredients,
instructions,
};
});
setCakes(newCakes);
console.log(newCakes);
} else {
setCakes([]);
}
setLoading(false);
} catch (error) {
console.log(error);
setLoading(false);
}
};
useEffect(() => {
fetchCakes();
}, []);
return (
<AppContext.Provider
value={{
loading,
cakes,
setSearchTerm,
searchTerm,
filteredData,
setFilteredData,
}}
>
{children}
</AppContext.Provider>
);
};
// make sure use
export const useGlobalContext = () => {
return useContext(AppContext);
};
export { AppContext, AppProvider };
SearchForm.js
import React from "react";
import { useGlobalContext } from "../context";
import CakeList from "./CakeList";
const SearchForm = () => {
const { cakes, setSearchTerm, searchTerm, setFilteredData } =
useGlobalContext;
const searchCakes = () => {
if (searchTerm !== "") {
const filteredData = cakes.filter((item) => {
return Object.values(item)
.join("")
.toLowerCase()
.includes(searchTerm.toLowerCase());
});
setFilteredData(filteredData);
} else {
setFilteredData(cakes);
}
};
return (
<section className="section search">
<form className="search-form">
<div className="form-control">
<label htmlFor="name">Search Your Favourite Cake</label>
<input
type="text"
id="name"
onChange={(e) => searchCakes(e.target.value)}
/>
</div>
</form>
</section>
);
};
export default SearchForm;
CakeList.js:
import React from "react";
import Cake from "./Cake";
import Loading from "./Loading";
import { useGlobalContext } from "../context.js";
const CakeList = () => {
const { cakes, loading, searchTerm, filteredResults } = useGlobalContext();
if (loading) {
return <Loading />;
}
return (
<section className="section">
<h2 className="section-title">Cakes</h2>
<div className="cakes-center">
{searchTerm.length > 1
? filteredResults.map((cake) => {
return <Cake key={cake.id} {...cake} />;
})
: cakes.map((item) => {
return <Cake key={item.id} {...item} />;
})}
</div>
</section>
);
};
export default CakeList;
App.js:
import React from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
// import pages
import Home from "./pages/Home";
import About from "./pages/About";
import SingleCake from "./pages/SingleCake";
import Error from "./pages/Error";
// import components
import Navbar from "./components/Navbar";
function App() {
return (
<Router>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/cake/:id" element={<SingleCake />} />
<Route path="*" element={<Error />} />
</Routes>
</Router>
);
}
export default App;
Can someone please help me with this search form? I have tried so many things and nothing is working :( Anyone?
On line 11 of SearchForm.js, there is a part that reads cakes.filter(. To resolve the typeError, change this to cakes?.filter(. This will only execute the filter if cakes is defined. It's a feature in javascript called Optional Chaining, introduced in ES2020.
Learn about it more here
I have a (Map) component dynamically imported to my page.
const Map = dynamic(() => import('../components/Mapcomp'), { ssr: false, })
From that component I also want to import a variable.
const [taskImg, setTaskImg] = useState(null);
export {taskImg};
The component is dynamically imported because otherwise I get a window is not defined error, and this is the solution for that.
Same with the variable. If I want to import it I get the above error.
But I need to use the taskImg variable in this page.
How can I do that?
Mapcomp:
import { MapContainer, TileLayer, useMap, Marker, Popup,
ImageOverlay } from 'react-leaflet'
import { useEffect, useState } from "react";
import Head from "next/head"
import { LatLngBounds } from 'leaflet';
const Map = () => {
const [userPos, setUserPos] = useState(null)
const [taskPos, setTaskPos] = useState(null)
const [task, setTask] = useState()
const [taskImg, setTaskImg] = useState(null);
const bounds = new LatLngBounds([81.505, -0.09], [50.773941, -84.12544])
useEffect(() => {
function getRandomTask(arr) {
const randomIndex = Math.floor(Math.random() * arr.length);
const item = arr[randomIndex];
return item;
}
const tasks = [
"boller",
"placeholder"
];
setTask(getRandomTask(tasks));
},[])
useEffect(() => {
if(task == "boller"){
console.log("boller")
setTaskImg("/sf2.jpg")
} else if(task == "placeholder") {
console.log("placeholder")
}
},[task])
return (
<>
<Head>
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.5.1/dist/leaflet.css"
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.5.1/dist/leaflet.js"
integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og=="
crossorigin=""></script>
</Head>
<MapContainer
className='absolute h-[750px] w-[750px] left-[45%] top-[80px] bg-no-repeat bg-cover bg-[#738aaf]'
center={[71.505, -40.09]} zoom={3} scrollWheelZoom={true} noWrap={true}>
<ImageOverlay
url="/allmaphres.png"
bounds={bounds}
opacity={1}
zIndex={10}
/>
</MapContainer>
</>
);
}
export default Map;
page (mapcomp is rendered here):
import { memo, useEffect, useMemo, useState } from "react";
import dynamic from 'next/dynamic'
import Navbar from "../components/Navbar";
import Footer from "../components/Footer";
import Head from "next/head";
const Map = dynamic(() => import('../components/Mapcomp'), {
ssr: false,
})
const All = () => {
return (
<>
<Navbar />
<div className="bg-white w-[500px] h-[100vh]">
<div className="task border-4 border-red-500 h-[250px]">
{/* taskImg && <img src={taskImg}/> */}
</div>
<div className="flex justify-center gap-[200px] text-xl">
<span>Tasks:</span>
<span>Points:</span>
</div>
<div className="flex justify-center gap-[240px] text-xl">
<span>X</span>
<span>X</span>
</div>
</div>
<Map />
<Footer />
</>
);
}
export default All;
You can't export a state to another component you either need to use a state management library like redux or create a context which make the state available for all the other components
I am trying to wrap my mind around this and find the breaking point for all morning but am not able to. I have only followed the official docs until now.
I need to update the theme from dark to light in a React App but the state wont change (or resets immediately)
Heres my code:
App.tsx
import React, { createContext, useMemo, useState } from 'react';
import styles from './App.module.scss';
import {createTheme,CssBaseline,PaletteMode,responsiveFontSizes,ThemeProvider,
useMediaQuery} from '#mui/material';
import { getDefaultThemeMode } from './shared/theme/default-theme-mode';
import { getDesignTokens } from './shared/theme/mui-design-tokens';
import Main from './main/Main';
import { Navigate, Route, Routes } from 'react-router-dom';
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import { OPTIONS } from './shared/i18n/translations';
export const ColorModeContext = React.createContext({
toggleColorMode: () => { },
});
function App() {
// THEME
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const [mode, setMode] = React.useState<'light' | 'dark'>('light');
React.useEffect(() => {
setMode(prefersDarkMode ? 'dark' : 'light');
}, [prefersDarkMode]);
const colorMode = React.useMemo(
() => ({
toggleColorMode: () => {
setMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light'));
},
}),
[]
);
let theme = React.useMemo(
() =>
createTheme(getDesignTokens(mode)),
[mode]
);
theme = responsiveFontSizes(theme);
return (
<ColorModeContext.Provider value={colorMode}>
<ThemeProvider theme={theme}>
<div className={styles.app} style={{background: theme.palette.background.default}}>
<CssBaseline/>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/>
<Routes>
<Route path='/home' element={<Main/>}/>
<Route path='*' element={<Navigate to='home'/>}/>
</Routes>
</div>
</ThemeProvider>
</ColorModeContext.Provider>
);
}
export default App;
getDesignTokens Function:
const getDesignTokens = (mode: PaletteMode): ThemeOptions => ({
palette: {
mode,
...(mode === 'light' ? {
primary: {
main: '#3c3c3c',
},
} : {
primary: {
main: '#3c3c3c',
},
})
}});
And finally, I am trying to update the theme from outside the App.tsx component this way:
const ThemeToggle = () => {
const theme = useTheme();
const colorMode = useContext(ColorModeContext);
return (
<>
<label htmlFor='theme-toggle' className={`${styles.toggleBtn}
${theme.palette.mode === 'dark' ? styles.dark : ''}`}
onClick={colorMode.toggleColorMode}>
<input type='checkbox' id='theme-toggle' className={styles.input}/>
</label>
</>
)
}
export default ThemeToggle;
I must be missing something obvious but have tried everything. Anyone has done something similar?
I have a lot of globally declared states in my application. I used useContext for implementing it, however, I keep getting a bunch of errors in the console regarding useContext.
Error:
Warning: useContext() second argument is reserved for future use in React. Passing it is not supported. You passed: false.
in Navbar (at Home.js:11)
in Home (created by Context.Consumer)
in Route (at App.js:96)
in Switch (at App.js:76)
in Router (created by BrowserRouter)
in BrowserRouter (at App.js:74)
in App (at src/index.js:7)
in StrictMode (at src/index.js:6)
App.js:
import React, { useState, useEffect } from 'react';
import { Redirect } from 'react-router-dom';
import './App.css';
import Home from '../pages/Home';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Restaurants from '../pages/Restaurants';
import ScrollToTop from '../components/ScrollToTop';
import UserAccount from '../pages/UserAccount'
import Footer from '../components/footer/Footer';
import { UserContext } from '../UserContext';
function App() {
const [clickedDistrict, setClickedDistrict] = useState(false);
const [clickedSuggestion, setClickedSuggestion] = useState(false);
const [checkedDistance, setCheckedDistance] = useState("1000")
const [restaurants, setRestaurants] = useState([]);
const [clickedUserMenuItem, setClickedUserMenuItem]
= useState("saved")
const [goodPassword, setGoodPassword] = useState(false)
const [chosenRestaurant, setChosenRestaurant] = useState(false);
const [generalSearchPath, setGeneralSearchPath] = useState(false);
const [incorrectPassword, setIncorrectPassword] = useState(false);
const [successfullLogin, setSuccessfullLogin] = useState(false)
const [username, setUsername] = useState(false)
const [incorrectOldPassword, setIncorrectOldPassword] = useState(false)
const [logout, setLogout] = useState(false);
const [newUsername, setNewUsername] = useState(false)
const [incorrectPasswordOnDelete, setIncorrectPasswordOnDelete] = useState(false)
const [deleteAccount, setDeleteAccount ] = useState(false)
return (
<>
<Router>
<ScrollToTop />
<Switch>
<UserContext.Provider value={{
clickedDistrict, setClickedDistrict,
clickedSuggestion, setClickedSuggestion,
checkedDistance, setCheckedDistance,
restaurants, setRestaurants,
clickedUserMenuItem, setClickedUserMenuItem,
goodPassword, setGoodPassword,
chosenRestaurant, setChosenRestaurant,
generalSearchPath, setGeneralSearchPath,
incorrectPassword, setIncorrectPassword,
successfullLogin, setSuccessfullLogin,
username, setUsername,
incorrectOldPassword, setIncorrectOldPassword,
logout, setLogout,
newUsername, setNewUsername,
incorrectPasswordOnDelete, setIncorrectPasswordOnDelete,
deleteAccount, setDeleteAccount
}}>
<Route path='/' exact component={Home} />
<Route path='/restaurants' component={Restaurants} />
{ (successfullLogin && !logout && !deleteAccount) ?
<Route path='/user' component={UserAccount} />
:
<>
<Route path='/user' component={UserAccount} />
<Redirect to='/' /></>
}
</UserContext.Provider>
</Switch>
<Footer />
</Router>
</>
);
}
export default App;
UserContext.js:
import { createContext } from "react";
export const UserContext = createContext();
I tried searching about this warning but nothing helped. I don't even understand the reason for this error. Which second argument does it imply?
Also, the weird thing is that I have theese states used throughout the application, but the error shows that I have a problem in the navbar on the Home page.
Home:
import React from 'react';
import Cards from '../components/cards/Cards';
import HeroSection from '../components/hero/HeroSection';
import Districts from '../components/districts/Districts';
import Navbar from '../components/navbar/Navbar';
import CollegeSection from '../components/college/CollegeSection';
function Home() {
return (
<>
<Navbar />
<HeroSection />
<Cards />
<CollegeSection />
<Districts />
</>
);
}
export default Home;
import React, { useEffect, useContext } from 'react';
import { Button } from '../button/Button';
import MobileNavbar from './MobileNavbar'
import { Link } from 'react-router-dom';
import './Navbar.css';
import { Modal } from '../forms/Modal'
import Searchbox from '../search/Searchbox';
import NavbarLogic from './NavbarLogic';
import { UserContext } from '../../UserContext';
import UserNavbar from '../user/UserNavbar';
function Navbar() {
const { click, button, showButton,
handleClick, closeMenuDiscardChanges, closeMenuOpenPCRestaurants }
= MobileNavbar();
const { navMenuClassName, searchbox, showLogInModal,
showSignUpModal, openLogInModal, openSignUpModal,
setShowLogInModal, setShowSignUpModal }
= NavbarLogic();
const { successfullLogin, setSuccessfullLogin, logout }
= useContext(UserContext);
useEffect(() => {
showButton();
}, [showButton]);
useEffect(() => {
if (logout) {
setShowLogInModal(false);
setSuccessfullLogin(false)
}
}, [logout,setSuccessfullLogin,setShowLogInModal])
window.addEventListener('resize', showButton);
return (
<>
<nav className={click ? 'navbar active' : 'navbar'}>
<div className='navbar-container'>
<Link to='/' className='navbar-logo' onClick={closeMenuDiscardChanges}>
Restaurateur<i class="fas fa-utensils" />
</Link>
<div className={click ? 'hidden' : searchbox}>
<Searchbox />
</div>
<div className='menu-icon' onClick={handleClick}>
<i className={click ? 'fas fa-times' : 'fas fa-bars'} />
</div>
<ul className={click ? 'nav-menu active' : navMenuClassName}>
<li className='nav-item'>
<Link to='/' className='nav-links' onClick={closeMenuDiscardChanges}>
Home
</Link>
</li>
<li className='nav-item'>
<Link
to='/restaurants'
className='nav-links'
onClick={setRestaurantsNavLink() === "All Restaurants" ?
closeMenuDiscardChanges
:
closeMenuOpenPCRestaurants}
>
{setRestaurantsNavLink()}
</Link>
</li>
<li>
<Link
className='nav-links-mobile'
onClick={openLogInModal}
>
Log In
</Link>
<Link
className='nav-links-mobile'
onClick={openSignUpModal}
>
Sign Up
</Link>
</li>
</ul>
{successfullLogin === true ?
<UserNavbar />
:
<>
{button &&
<Button
buttonStyle='btn--outline'
buttonSize='btn--medium'
onClick={openLogInModal}
id="login">
LOG IN
</Button>}
<Modal
showLogInModal={showLogInModal}
setShowLogInModal={setShowLogInModal}
/>
{button &&
<Button
id="signup"
buttonSize='btn--medium'
onClick={openSignUpModal}>
SIGN UP
</Button>}
<Modal
showSignUpModal={showSignUpModal}
setShowSignUpModal={setShowSignUpModal}
/>
</>}
</div>
</nav>
</>
);
}
export default Navbar;
How can I get rid of this useContext warning?
Edit:
This is how I use useContext in Mobilenavbar:
import { useState, useContext } from 'react';
import { UserContext } from "../../UserContext"
const MobileNavbar = () => {
const [click, setClick] = useState(false);
const [button, setButton] = useState(true);
const { setPragueCollegePath } = useContext(UserContext)
const { setClickedDistrict, setClickedSuggestion } = useContext(UserContext)
const { setChosenRestaurant, setGeneralSearchPath } = useContext(UserContext);
const handleClick = () => setClick(!click);
const closeMenuOpenRestaurants = () => {
setClick(false);
setClickedDistrict(false);
setClickedSuggestion(false);
setChosenRestaurant(false);
setGeneralSearchPath(false)
}
const closeMenuOpenPCRestaurants = () => {
setClick(false);
setClickedDistrict(false);
setClickedSuggestion(false);
setChosenRestaurant(false);
setGeneralSearchPath(false);
}
const closeMenuDiscardChanges = () => {
setClick(false);
setClickedDistrict(false)
setClickedSuggestion(false)
setChosenRestaurant(false)
setGeneralSearchPath(false);
}
const showButton = () => {
if (window.innerWidth <= 1120) {
setButton(false);
} else {
setButton(true);
}
};
const showSearch = () => {
if (window.innerWidth <= 820) {
setButton(false);
} else {
setButton(true);
}
};
return {
click, button, showButton, handleClick,
showSearch, closeMenuOpenRestaurants,
closeMenuOpenPCRestaurants, closeMenuDiscardChanges
}
}
export default MobileNavbar;
And here is NavbarLogic:
const {successfullLogin, setSuccessfullLogin, logout }
= useContext(UserContext);
I usually import all the variables together.