Thumbnail gallery layout is broken until resizing window or opening dev tools

I’m using Glide.js along with Twig and vanilla JavaScript to create a gallery with one main image and a thumbnail slider. The thumbnails should display vertically (or horizontally on certain breakpoints), and everything works after I open DevTools or resize the window — but on initial load, the layout is broken (thumbnails are misaligned or not transformed correctly).

Here’s how I’m mounting everything:

window.onload = function () {
    const glideMain = new Glide('.glide-main', {
      type: 'carousel',
      perView: 1,
      autoplay: false,
      gap: 0,
      animationDuration: 500,
    });
  
    const glideThumb = new Glide('.glide-thumb', {
      type: 'slider',
      focusAt: 0,
      dragThreshold: 0,
      animationDuration: 500,
    });
  
    const thumbSlides = document.querySelectorAll('.glide-thumb .glide__slide');
  
    // Function to apply z-index fix
    function applyZIndexFix() {
      document.querySelectorAll('.glide__thumb, .glide__thumb > img').forEach(el => {
        el.style.zIndex = '999';
      });
    }
  
    thumbSlides.forEach((slide, index) => {
      slide.addEventListener('click', function (e) {
        e.preventDefault();
        glideMain.go('=' + index);
        setActiveThumbnail(index);
      });
    });
  
    function setActiveThumbnail(index) {
      thumbSlides.forEach(slide => slide.classList.remove('active'));
      if (thumbSlides[index]) {
        thumbSlides[index].classList.add('active');
      }
      applyZIndexFix();
    }
  
    setActiveThumbnail(0);
  
    function updateThumbTransformVertical(activeIndex) {
      const thumbContainer = document.querySelector('.glide-thumb .glide__slides');
      const containerHeight = document.querySelector('.glide-thumb').offsetHeight;
      const totalSlides = thumbSlides.length;
  
      const slideHeight = thumbSlides[0]?.offsetHeight + 10 || 0;
      const maxTranslate = (totalSlides * slideHeight) - containerHeight;
  
      const centerIndex = 2;
      let translateY = 0;
  
      if (activeIndex <= centerIndex) {
        translateY = 0;
      } else if (activeIndex >= totalSlides - centerIndex - 1) {
        translateY = maxTranslate;
      } else {
        translateY = (activeIndex - centerIndex) * slideHeight;
      }
  
      if (activeIndex === totalSlides - 1 || activeIndex === totalSlides - 2 || activeIndex === totalSlides - 3) {
        translateY -= 10;
      }
  
      thumbContainer.style.transition = 'transform 0.5s ease';
      thumbContainer.style.transform = `translate3d(0, ${-translateY}px, 0)`;
  
      applyZIndexFix();
    }
  
    function updateThumbTransformHorizontal(activeIndex) {
      const thumbContainer = document.querySelector('.glide-thumb .glide__slides');
      const containerWidth = document.querySelector('.glide-thumb').offsetWidth;
      const totalSlides = thumbSlides.length;
  
      const slideWidth = thumbSlides[0]?.offsetWidth + 10 || 0;
      const maxTranslate = (totalSlides * slideWidth) - containerWidth;
  
      const centerIndex = 2;
      let translateX = 0;
  
      if (activeIndex <= centerIndex) {
        translateX = 0;
      } else if (activeIndex >= totalSlides - centerIndex - 1) {
        translateX = maxTranslate;
      } else {
        translateX = (activeIndex - centerIndex) * slideWidth;
      }
  
      thumbContainer.style.transition = 'transform 0.5s ease';
      thumbContainer.style.transform = `translate3d(${ -translateX }px, 0, 0)`;
  
      applyZIndexFix();
    }
  
    glideMain.on('run', function () {
      setActiveThumbnail(glideMain.index);
  
      const width = window.innerWidth;
      if (width >= 768 && width <= 1131) {
        updateThumbTransformHorizontal(glideMain.index);
      } else {
        updateThumbTransformVertical(glideMain.index);
      }
    });
  
    glideMain.mount();
    applyZIndexFix(); // Apply z-index after mounting
  
    function checkScreenWidth() {
      const width = window.innerWidth;
  
      if (width >= 1132 || width < 768) {
        document.querySelector('.glide-thumb').classList.remove('horizontal');
        glideThumb.mount();
      } else if (width >= 768 && width <= 1131) {
        document.querySelector('.glide-thumb').classList.add('horizontal');
        glideThumb.mount();
      }
  
      applyZIndexFix();
    }
  
    checkScreenWidth();
  
    window.onresize = function () {
      checkScreenWidth();
    };
  
    setTimeout(() => {
      updateThumbTransformVertical(glideMain.index);
    }, 100);
  };

Before trigger

After

As I see initially it has width: 0 px and after triggering screen width it gets the real width value which is appropriate.

How to call afterDraw, afterLayout or afterUpdate chartjs v4

I am trying to call afterUpdate, afterLayout or afterDraw

I try to directly put this in plugns or annotatinos,

However nothing works, how can I make this correctly?

What I want to do is written here, but this is chartjs v2.

How to add images as labels to Canvas Charts using chart.js

const bar_options = {
  responsive: true,
  indexAxis: 'y',
  plugins: {
    afterUpdate: chart => {
      console.log("test afterUpdate");
    }  ,
    afterLayout: chart => {
      console.log("test afterLayout");
    } , 
    afterDraw: chart => {  
      console.log("test afterDraw");
    },
    annotations:{
      afterUpdate: chart => {
        console.log("test in annotation afterUpdate");
      }  ,
      afterLayout: chart => {
        console.log("test in annotation afterLayout");
      }  
    },
  },
};

<Bar options={bar_options} data={mydata}/>

JS: Combining Library Promises and Sleep Function in Class

Problem Origin
I want to create a class that will use the sharp library for image processing. The class is also expected to return some data for further processing.

Since sharp has a “promise-based” nature and I’m very new to the concept of promises, I encountered some problems. I haven’t found the solution/explanation in other threads/topics/forums… Or, maybe, I just wasn’t able to wrap my mind about that.

Problem Description
I started writing a class that accepts a path to an image and reads some data from it. To be able to wait for the reading to finish before proceding further, I used a loop with the sleep function (don’t understand its code well enough, but nevertheless…). It even works somehow (I feel there may be some problems that arise in the future).

const sharp = require('sharp');

class Image {
  imgBuf;
  imgData;
  notReady = true;

  constructor(imgPath) {
    const img = sharp(imgPath);
    (async () => {
      this.imgBuf = await img.raw().toBuffer();
      this.imgData = await img.metadata();
      this.notReady = false;
    })();
  }
}

const sleep = ms => new Promise(r => setTimeout(r, ms));

(async () => {
  const imgPath = 'test.png';
  const image = new Image(imgPath);
  while (image.notReady) { await sleep(0); }  // <===========
  console.log(image.imgBuf);
})();

But if to move the sleeping loop to the class, the code is stuck in an infinite loop:

...
      this.notReady = false;
    })();
    while (this.notReady) { sleep(0); }  // <===========
...
  const image = new Image(imgPath);
  // while (image.notReady) { await sleep(0); }
...

Question: Why the latter code doesn’t work?

P.S.: Any suggestions/recommendations for the code are highly appreciated.

Request body of multiple file uploads in multipart formdata with unique metadata

I’m working on a NestJS app and in it, one route has file uploading in it. I am uploading the file and its metadata using form-data. Right now, I am able to upload just one file at a time and the form-data looks like this:

Key      Type     Value
file     File     some_file.pdf
name     Text     File Name
type     Text     document
category Text     profile

and so on and so forth.

My DTO looks like this:

export class UploadFileDto {
    @IsString()
    @Length(2, 255)
    name: string;
    @IsString()
    type: string;
    @IsString()
    category: string;
    @IsOptional()
    force: string = 'false';
}

This works fine for just one file. My question now is that I want to be able to upload multiple files and all of those files would have their unique metadata. How can I do this and how can I structure my form-data to handle this?

My HTML website is wrong in Iphone browser

I have a website and it works correctly in Desktop and Androids.

When I check my website in Iphone, there are 2 things that are wrong

  1. Size Value in HTML input tag does not increase the size of input but it depends on Max Value

  2. When i scroll down my website while it loads more contents, the page scroll up to the beginning which is different in Desktop and Androids.

Is there any solution to fix this like changing some my HTML and Javascript codes in order it to work correctly in Iphone browser?

These are my codes:

<input  min="1" max="200" value="1" maxlength="7" required size="7">

if ((window.innerHeight + window.scrollY) >= (document.body.offsetHeight - 50)){//Loads}

Replacing and formatting “Yes” or “No” text replacement from submitted Google Form within Google Docs

I’m currently making a generated Google Document prefilled with answers using a created template to replace text from a Google Form/Sheet using the Apps Script. I’ve taken a pre-existing template for my script and I’m trying to edit it to work. However, I want to replace the vaule in a certain part of the body with different text if the answer is “Yes” in the form (The “Fatigue related health or safety issues”) or remove/delete the text line entirely if the answer is “No”. It just takes the vaule of the submitted cell in the Google Sheet at the moment (Which is just “Yes” or “No” from the single choice selection for the specific part I want to replace on the Google form upon submission).

I have tried this so far but I keep returning errors (At if Line statement when I attempt to save it) and I am not sure how to change my working to get it behave the way I want to

function JSAGoogleFormFill(e) {
  var Timestamp = e.values[0];
  var Event = e.values [1];
  //(Vaules same as listed above, Abridged)
  var Fatigue_related_health_or_safety_issues = e.values [10];

  
  var FinalDocument = DriveApp.getFileById("FILE"); 
  var FinalResponse = DriveApp.getFolderById("FOLDER");

  var copy = FinalDocument.makeCopy(Start_Date+', '+Event, FinalResponse);
  
  var doc = DocumentApp.openById(copy.getId());

  var body = doc.getBody();

  body.replaceText ("{{Event}}", Event);
  //(Abridged here)
  body.replaceText ("{{Fatigue}}", Fatigue_related_health_or_safety_issues);
   if body.replaceText "Yes" {
    "Fatigue related health or safety issues";
   }
   else body.replaceText "No" {
    body.editAsText().deleteText;
   }
  


  doc.saveAndClose();

  }

Any Help is greatly appricated! Thanks in advance

Node.JS: how do I set an environment variable in 1 file to be read all others?

I have a bunch of files that run various tests and return results to a log file.

I have helper functions that create and log file and add to it.

I want to dynamically name that log file, based off the time and date of when the script is run. To that end I need to store the file’s name in a variable on the file that triggers all the tests (main.js) and make it available to the functions in my helper-function.js file.

I’ve been experimenting with setting a environmental variable on main.js but have had no success getting all the helper functions to read it.

Whilst it seems I can set it on main.js and have the createLogs() function use it, the subsequent updateLogs() function, which is exported (module.exports = {updateLogs}) to other files, cannot. I’m guessing the other files are simply not “aware” of the environment variable.

However, hard coding the environment variable in helper-functions.js works – both helper functions can see it and use it.

Does anyone know a way I can set process.env.LOGFILE with a dynamic value and make it available to all helper functions? (note: due to security restrictions I cannot use 3rd party packages to achieve this).
`

My files are as such:

//main.js
const d = new Date();
const logName = "fooBar";
process.env.LOGFILE = logName + "-" + d.getDay() + "-" + d.getMonth() + "-" + d.getFullYear()  +  ".json";
createLogs(logName);

// Running tests on other files...

helper-functions.js

//If I uncomment the below it works, but file name is hard coded.
//process.env.LOGFILE = "customLogs.json";
    
//Create log file when scripts are first run
const createLogs = (logName) => {
    exec('git branch --show-current', (err, stdout, stderr) => {
        if (err) {
            console.log("Error getting git branch:" + stderr);
        }

        const startTime = ((Date()).toLocaleString()).split('GMT')[0];
        const branchName = stdout ? stdout.replace(/(rn|n|r)/gm,"") : "no-branch";

        let repObjString = `{"details":{"name": "${logName}","time": "${startTime}","branch": "${branchName}"},"report":{}}`;

        const logFileName = `logs/${process.env.LOGFILE}`; //<== THIS WORKS
        if (!fs.existsSync(logFileName)) {
            console.log("Log doesnt exist. Making one...");
            fs.writeFile(logFileName, repObjString, function (err) {
                if (err) throw err;
                console.log('Creating file!');
            });
        }
    });
}

// Update logs
const updateLogs = (logObj) => {
    const logName = `logs/${process.env.LOGFILE}`; //<== THIS DOES NOT WORK

    fs.readFile(logName, 'utf8', function (err, logData) {
        if (err) throw err;
        Object.assign(logData["report"], logObj);
        fs.writeFile (logName, logData, function(err) {
            if (err) throw err;
            console.log('Log updated');
        });
    });
}

Not able to change style.display with javascript

First time I’ve posted a coding question on here. I’ve nearly completed a JS/HTML/CSS game and will be uploading to Steam soon. Long story short, I’ve run into a snag, needing to move all inline styles in HTML into an external css file. In doing this, my working code seems to have broken. I’ve boiled it down to this question: Why does the button in the code below not display the div? With all styling moved to an external CSS file, how can I get javascript lines such as document.getElementById(“id”).style.display = “” to work with minimal adjustments to my thousands of lines of code?

CSS:

#testID {
    display: none;
}

HTML:

<div id="testID">
    1234
</div>
<div>
    <button onclick="showFn()">Show</button>
</div>

Javascript:

function showFn() {
  document.getElementById("testID").style.display = ""
}

Trigger onclick event after long touch

I’m currently developing an Android App using a WebView and realized that the behavior of click events differs between desktop and mobile.

<button onclick="console.log('clicked')" />

On desktop when pressing a button and releasing after some milliseconds, the click-event is fired as expected.
On mobile the click event is only fired after very briefly touching the button. Long presses are ignored.

I would like the app to behave mostly like other (native) apps. Is there a way to also trigger click events when touching the button for a longer period?

Inner function not being called after loop exit

I’ve been doing The Odin Project and am on the Rock, Paper, Scissors assignment.

I’ve created a function to play 5 rounds of RPS and keep track of the score for the human/user and the computer. This part works fine.

The five rounds run through a for loop, which has no issues, then after the loop, it should call declareWinner(), but it doesn’t do anything once the initial 5-round loop is finished. No error message, nothing.

I would really appreciate it if you could take a look at the code below and let me know what you think.

I’m sure there’s some rookie mistake in there, but I can’t figure it out for the life of me. Also, feel free to provide any other criticisms, advice, feedback, and whatnot that will make me a better coder.

To narrow down if the issue is in the declareWinner() function or not, I’ve tried adding a regular console.log() in its place at the exit of the loop to see if that will run. Alas, it does not. The loop exits and that’s all she wrote.

Thanks!

//CODE:

function getComputerChoice() {
    const number = Math.floor(Math.random() * 3 + 1);
    if (number === 1) return "rock";
    else if (number === 2) return "paper";
    else if (number === 3) return "scissors"; 
}

let humanScore = 0;
let computerScore = 0;

function playRound(humanChoice, computerChoice) {
    if (humanChoice === null) {
        console.log("Game canceled. No choice made.");
        return; // Exit early
    };
    if (humanChoice === computerChoice) {
        console.log(`It's a draw! The score is still ${humanScore} for the human and ${computerScore} for the computer!`);
    } else if (humanChoice === "rock" && computerChoice === "scissors") {
        console.log("Rock beats scissors! Meatbag wins!");
        humanScore++;
        console.log(`Human score is now ${humanScore}. The computer's score is ${computerScore}.`);
    } else if (humanChoice === "rock" && computerChoice === "paper") {
        console.log("Paper beats rock. The machine wins!");
        computerScore++
        console.log(`Human score is now ${humanScore}. The computer's score is ${computerScore}.`);
    } else if (humanChoice === "paper" && computerChoice === "rock") {
        console.log("Paper beats rock! Meatbag wins!");
        humanScore++;
        console.log(`Human score is now ${humanScore}. The computer's score is ${computerScore}.`);
    } else if (humanChoice === "paper" && computerChoice === "scissors") {
        console.log("Scissors beats paper! Machine wins!");
        computerScore++;
        console.log(`Human score is now ${humanScore}. The computer's score is ${computerScore}.`);
    } else if (humanChoice === "scissors" && computerChoice === "paper") {
        console.log("Scissors beats paper! Meatbag wins! What a play!");
        humanScore++;
        console.log(`Human score is now ${humanScore}. The computer's score is ${computerScore}.`);
    } else if (humanChoice === "scissors" && computerChoice === "rock") {
        console.log("Rock beats scissors! Meatbag loses.");
        computerScore++;
        console.log(`Human score is now ${humanScore}. The computer's score is ${computerScore}.`);
    }
}

function declareWinner() {
    if (humanScore > computerScore) {
        console.log(`That's it, folks! Meatbag wins ${humanScore} to ${computerScore}!`);
    } else {
        console.log(`That's it, folks! Computer wins ${computerScore} to ${humanScore}!`);
    }
}

function playGame() {
    for (let i = 0; i < 5; i++) {
        let humanChoice = prompt("Ready to play? Rock... paper... scissors!");
        let computerChoice = getComputerChoice();
        console.log(`Meatbag picks ${humanChoice.toLowerCase()} and The Machine picks ${computerChoice}.`);
        playRound(humanChoice, computerChoice);
    } 
    declareWinner();
}

playGame();

When the modal/dialog tag is open the selected id is wrong

I’m creating a simple CRUD, it’s already create, read and delete but does not update properly yet.

When the modal/dialog tag gets opened, for some reason the id of the collect is wrong, it always get the id of the first collect in the list.

for example, if there is id 1, 2 and 3 in the list and I click to edit the id 3, the modal/dialong tag gets opened, but the id is 1 and instead of updating the item list I’m clicking it always update the first item of the list.

this is part of the code where the collects are displayed and has the EditModal component.

import axios from "axios";
import {useState, useEffect} from "react";
import EditModal from "./EditModal.jsx";

function DisplayCollects() {

    const [data, setData] = useState([]);
    const [input, setInput] = useState({
        company: "",
        date: "",
        product: "",
    })

    useEffect(() => {
        async function fetchData() {
            try {
              const result = await axios("http://localhost:3000/");
              setData(result.data);
            }
            catch (err) {
              console.error(err);
            }
            
          }

          fetchData();
    }, [])

    function handleInput(event) {
        const {name, value} = event.target;
        if (name == "company") {
            setInput({...input, company: value});
        }
        if (name == "date") {
            setInput({...input, date: value});
        }
        if (name == "product") {
            setInput({...input, product: value});
        }
    }

    async function addCollect() {
        try {
            await axios.post("http://localhost:3000/add", input);
            window.location.reload();
        }
        catch (err) {
            console.error(err);
            window.alert(err);
        }
    }

    async function doneCollect(itemId) {
        try {
            await axios.post("http://localhost:3000/done", {itemId});
            window.location.reload();
        }
        catch (err) {
            console.error(err);
            window.alert(err);
        }
    }

    async function deleteCollect(itemId) {
        try {
            await axios.post("http://localhost:3000/delete", {itemId});
            window.location.reload();
        }
        catch (err) {
            console.error(err);
            window.alert(err);
        }
    }

    async function editCollect(input) {
        try {
            await axios.post("http://localhost:3000/edit", input);
            window.location.reload();
        }
        catch (err) {
            console.error(err);
            window.alert(err);
        }
    }

    return (
        <table>
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Empresa</th>
                    <th>Data</th>
                    <th>Material</th>
                </tr>
            </thead>
            <tbody>
            {data.map((item, index) =>
                <tr key={index} className="mainRow">
                    <td>{item.id}</td>
                    <td>{item.company}</td>
                    <td>{item.date}</td>
                    <td>{item.product}</td>
                    <td><img onClick={() => doneCollect(item.id)} src="/assets/images/done.png" alt="done button"/></td>
                    <td><EditModal id="form" editCollect={editCollect} itemId={item.id}/></td>
                    <td><img onClick={() => deleteCollect(item.id)} src="/assets/images/delete.png" alt="delete button"/></td>
                </tr>
            )} 
            </tbody>
            <tbody>
                <tr>
                    <td></td>
                    <td><input onChange={handleInput} value={input.company} type="text" name="company" placeholder="Empresa"/></td>
                    <td><input onChange={handleInput} value={input.date} type="text" name="date" placeholder="Data"/></td>
                    <td><input onChange={handleInput} value={input.product} type="text" name="product" placeholder="Material"/></td>
                    <td><img src="/assets/images/add.png" alt="add button" onClick={addCollect}/></td>
                </tr>
            </tbody>
        </table>
    )
}

export default DisplayCollects;

this is the EditModal component:

import { useState } from "react";

function EditModal({editCollect, itemId}) {

    console.log(itemId);
    const [input, setInput] = useState({
        input: itemId,
        company: "",
        date: "",
        product: "",
    });

    function handleInput(event) {
        const {name, value} = event.target;
        if (name == "company") {
            setInput({...input, company: value});
        }
        if (name == "date") {
            setInput({...input, date: value});
        }
        if (name == "product") {
            setInput({...input, product: value});
        }
    }

    function openDialog() {
        const dialog = document.getElementById("form");
        dialog.showModal();
    }

    return (
        <>
            <dialog id="form">
                <table>
                    <thead>
                        <tr>
                            <th>Empresa</th>
                            <th>Data</th>
                            <th>Material</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td><input onChange={handleInput} value={input.company} type="text" name="company" placeholder="Empresa"/></td>
                            <td><input onChange={handleInput} value={input.date} type="text" name="date" placeholder="Data"/></td>
                            <td><input onChange={handleInput} value={input.product} type="text" name="product" placeholder="Material"/></td>
                            <td><img onClick={() => editCollect(input)} src="/assets/images/done.png" alt="done button"/></td>
                        </tr>
                    </tbody>
                </table>
            </dialog>
            <img onClick={openDialog} src="/assets/images/edit.png" alt="edit button"/>
        </>
    )
}

export default EditModal;

and this is the backend:

app.post("/edit", async (req, res) => {
    console.log(req.body);
    try {
        await db.query("UPDATE coletas SET company = $1, date = $2, product = $3 WHERE id = $4", [req.body.company, req.body.date, req.body.product, req.body.input]);
        res.send("ok");
    }
    catch (err) {
        console.error(err);
    }
})

an image to better illustrate, the first 3 consoles are the id of each item in the list, I clicked to edit the last item, but when I’m typing it logs the id of first item and send the id of first item to the backend if I click the done button.

enter image description here

updates react-leaflet clusters and markers

please explain why when updating markers on the map, all clusters disappear for a moment, and then reappear. How do I make marker updates happen seamlessly for the user?

this is code parent component MapForm:

import { observer } from "mobx-react-lite";
import {
  MapContainer,
  Marker,
  Popup,
  TileLayer,
  Polyline,
  LayersControl,
  LayerGroup,
  Circle,
  FeatureGroup,
  Rectangle,
  useMap,
} from "react-leaflet";
import "leaflet/dist/leaflet.css";
import L, { rectangle } from "leaflet";
import Form from "react-bootstrap/Form";
import "bootstrap/dist/css/bootstrap.min.css";
import styles from "./MapForm.module.css";
import DynamicMarkersLayer from "./DynamicMarkersLayer";

// Импортируем изображения маркеров
import markerIcon from "leaflet/dist/images/marker-icon.png";
import markerIcon2x from "leaflet/dist/images/marker-icon-2x.png";
import markerShadow from "leaflet/dist/images/marker-shadow.png";
import { useContext, useEffect } from "react";
import { Context } from "../../main";
// Фикс для маркеров
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
  iconRetinaUrl: markerIcon2x,
  iconUrl: markerIcon,
  shadowUrl: markerShadow,
});

// Создаем отдельный компонент для обработки событий карты
const MapEventHandler = observer(() => {
  const { store } = useContext(Context);
  const map = useMap();

  useEffect(() => {
    const debounceTimer = { current: null };

    const handleMoveEnd = () => {
      clearTimeout(debounceTimer.current);
      debounceTimer.current = setTimeout(() => {
        const bounds = map.getBounds();
        if (!store.prevBounds || !bounds.equals(store.prevBounds)) {
          store.sendBounds(bounds);
          store.prevBounds = bounds;
        }
      }, 300);
    };


    map.on("zoomend", handleMoveEnd);
    map.on("moveend", handleMoveEnd);

    handleMoveEnd(); // Первоначальная загрузка

    return () => {
      map.off("moveend", handleMoveEnd);
      map.off("zoomend", handleMoveEnd);
    };
  }, []);

  return null;
});

function MapForm() {
  const center = [55.75281851900141, 37.61597512353604];

  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
      <div className={styles.selectContainer}>
        <Form.Select aria-label="Выберите даты" className={styles.optionSelect}>
          <option>Выберите дату</option>
          <option value="1">Сегодня</option>
          <option value="2">Вчера</option>
        </Form.Select>
      </div>

      <div style={{ flex: 1, position: "relative" }}>
        <MapContainer
          center={center}
          zoom={10}
          style={{ height: "100%", width: "100%" }}
        >
          <TileLayer
            attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          />

          {/* Добавляем обработчик событий карты */}
          <MapEventHandler />

          <LayersControl position="topleft">
            <LayersControl.Overlay name="Wi-Fi_AP" checked>
              <DynamicMarkersLayer />
            </LayersControl.Overlay>

            <LayersControl.Overlay name="Трек" checked>
              <Marker position={center}>
                <Popup>A pretty CSS3 popup. <br /> Easily customizable.</Popup>
              </Marker>
            </LayersControl.Overlay>

            <LayersControl.Overlay checked name="Layer group with circles">
              <LayerGroup>
                <Circle
                  center={center} //Ваня пиздюн Б6
                  pathOptions={{ fillColor: "blue" }}
                  radius={200}
                />
                <Circle
                  center={center}
                  pathOptions={{ fillColor: "red" }}
                  radius={100}
                  stroke={false}
                />
                <Circle
                  center={[51.51, -0.08]}
                  pathOptions={{ color: "green", fillColor: "green" }}
                  radius={100}
                />
              </LayerGroup>
            </LayersControl.Overlay>
          </LayersControl>
        </MapContainer>
      </div>
    </div>
  );
}

export default observer(MapForm);

this is code DynamicMarkersLayer:

import { LayersControl, Marker, Popup, useMap } from "react-leaflet";
import { useContext, useEffect, useMemo, useRef } from "react";
import { observer } from "mobx-react-lite";

import { Context } from "../../main";
import MarkerClusterGroup from "react-leaflet-markercluster";
import "react-leaflet-markercluster/styles";


function DynamicMarkersLayer() {
  const { store } = useContext(Context);
  const m =[...store.markers]

  const markerHash = m.length > 0 ? m.reduce((acc, marker) => acc+marker.id) - Date.now() : 'empty';
  
  return (
    
    <MarkerClusterGroup
    key={`cluster - ${markerHash}`}
      chunkedLoading
      chunkInterval={100}
      spiderfyOnMaxZoom={true}
      showCoverageOnHover={false}
      maxClusterRadius={60}
      spiderLegPolylineOptions={{
        weight: 1,
        color: '#222',
        opacity: 0.5
      }}
      spiderfyDistanceMultiplier={1.5}
      animate={true}
      animateAddingMarkers={true}
      disableClusteringAtZoom={18}
      removeOutsideVisibleBounds={false}
    >
      {m.map((marker) => {
        // console.log(`${marker.id - marker.version || 0}`)
        return(
        <Marker
          key={`${marker.id - marker.version}`}
          // key='0'
          position={[marker.lat, marker.lng]}
        >
          {/* <Popup>
            <div>
              <h4>{marker.name}</h4>
              <p>Координаты: {marker.lat}, {marker.lng}</p>
            </div>
          </Popup> */}
        </Marker>
      )})}
    </MarkerClusterGroup>
  );
}

export default observer(DynamicMarkersLayer)

Now, when changing bounds, a response with a set of coordinates is correctly received from the server, but the old layer disappears for a moment on the map before it is displayed, which is inconvenient with frequent updating of the dataset.