React stop rerendering of parent component when slider is used

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;

15 thoughts on “React stop rerendering of parent component when slider is used”

Leave a Comment