UPDATE based on Jayce444's comment. I moved setting the timer outside of the component and this helped. Is a global variable the best idea tho?
let globalTimer = null;
const setSlidingTimer = (timer) => {
globalTimer = timer;
};
const SearchJobs = (props) => {
useEffect(() => console.log("<SearchJobs /> rendered"));
const [sliderValue, setSliderValue] = useState(20);
const sliderChangeHandler = (newValue) => {
clearTimeout(globalTimer);
const timer = setTimeout(setSliderValue, 300, newValue);
setSlidingTimer(timer);
};
ORIGINAL POST:
My React app suffers in performance from too many rerenders of a parent component because its children (mainly a slider) change the state too often when changing their value.
My idea (see sliderChangeHandler) was to wait sth like 300ms before updating the slider's value in the state to reduce the number of rerenders. Somehow this doesn't work yet. Is there anyone who could help me with especially the slider and apply a similar idea to the input box? Like wait 300ms before updating the state. If the user types or slides again, reset the 300ms timer.
Here is the parent code
import React, { useEffect, useState } from "react";
import Col from "react-bootstrap/Col";
import Button from "react-bootstrap/Button";
import InputGroup from "react-bootstrap/InputGroup";
import FormControl from "react-bootstrap/FormControl";
import Slider from "../UI/Slider/Slider";
const SearchJobs = (props) => {
useEffect(() => console.log("<SearchJobs /> rendered"));
const [sliderValue, setSliderValue] = useState(20);
const [address, setAddress] = useState("");
const [slidingTimeout, setSlidingTimeout] = useState("");
const sliderChangeHandler = (event, newValue) => {
clearTimeout(slidingTimeout);
const timer = setTimeout(setSliderValue, 300, newValue);
setSlidingTimeout(timer);
};
return (
<>
<Col xs={12} md={7}>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="inputGroup-sizing-default">
Adresse
</InputGroup.Text>
</InputGroup.Prepend>
<FormControl
aria-label="Address"
aria-describedby="inputGroup-sizing-default"
placeholder="myAddress"
value={address}
onChange={(event) => setAddress(event.target.value)}
/>
</InputGroup>
</Col>
<Col xs={12} md={5}>
<Slider value={sliderValue} change={sliderChangeHandler} />
</Col>
</>
);
};
export default SearchJobs;
And this is the slider component:
import React from "react";
import Typography from "@material-ui/core/Typography";
import Slider from "@material-ui/core/Slider";
const SliderComponent = (props) => {
const marks = [
{
value: 0,
label: "0 km",
},
{
value: 50,
label: "50 km",
},
];
function valuetext(value) {
return `${value} km`;
}
return (
<div className="ml-3 mr-3">
<Typography id="discrete-slider-always" gutterBottom>
Radius
</Typography>
<Slider
defaultValue={20}
value={props.sliderValue}
onChange={(event, newValue) => props.change(event, newValue)}
getAriaValueText={valuetext}
aria-labelledby="discrete-slider-always"
step={0.1}
min={0}
max={50}
marks={marks}
valueLabelDisplay="on"
/>
</div>
);
};
export default SliderComponent;
question from:
https://stackoverflow.com/questions/65910561/react-stop-rerendering-of-parent-component-when-slider-is-used 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…