反应:带有自定义钩子的滑块无法正常工作

时间:2019-08-09 15:54:06

标签: reactjs material-ui react-hooks

我正在尝试使用滑块ui元素创建自定义钩子。我的目标是能够从父元素访问滑块值,以便更新其他一些ui部分。

但是,似乎滑块值未正确更新:当用户尝试拖动滑块工具提示时,它仅移动了一步。似乎在调用useEffect之后不再跟踪鼠标事件。

该如何解决并保持平稳的拖动行为?

这是我的代码(sandbox):

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './demo';

ReactDOM.render(<Demo />, document.querySelector('#root')); 

demo.js

import React, { useEffect } from "react";
import useSlider from "./slider";

function CustomizedSlider() {
  const [CustomSlider, sliderValue] = useSlider("Slider", 50);

  useEffect(() => {
    console.log("Slider value: " + sliderValue);
  }, [sliderValue]);

  return <CustomSlider />;
}

export default CustomizedSlider;

slider.js

import React, { useState } from "react";
import { withStyles, makeStyles } from "@material-ui/core/styles";
import Paper from "@material-ui/core/Paper";
import Slider from "@material-ui/core/Slider";
import Typography from "@material-ui/core/Typography";

const useStyles = makeStyles(theme => ({...
}));

const PrettoSlider = withStyles({...
})(Slider);

export default function useSlider(label, defaultState) {
  const classes = useStyles();
  const [state, setState] = useState(defaultState);

  const CustomSlider = () => {
    return (
      <Paper className={classes.root}>
        <div className={classes.margin} />
        <Typography gutterBottom>{label}</Typography>
        <PrettoSlider
          valueLabelDisplay="auto"
          aria-label="pretto slider"
          defaultValue={50}
          value={state}
          onChange={(event, v) => {
            setState(v);
          }}
        />
      </Paper>
    );
  };

  return [CustomSlider, state];
}

非常感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

问题在于您的CustomSlider是每个渲染的新组件类型,因为它每次都是唯一的函数。这会导致它在每次渲染时都需要卸载/重新安装,而不仅仅是重新渲染,这会引起各种问题(如您所见)。

我认为您实际上只需要一个自定义组件,而不是自定义钩子。以下是一种结构化方式,只需对初始代码进行最少的更改即可。

demo.js

import React, { useEffect } from "react";
import CustomSlider from "./CustomSlider";

function CustomizedSlider() {
  const [value, setValue] = React.useState(50);

  useEffect(() => {
    console.log("Slider value: " + value);
  }, [value]);

  return <CustomSlider label="Slider" value={value} setValue={setValue} />;
}

export default CustomizedSlider;

CustomSlider.js

import React from "react";
import { withStyles, makeStyles } from "@material-ui/core/styles";
import Paper from "@material-ui/core/Paper";
import Slider from "@material-ui/core/Slider";
import Typography from "@material-ui/core/Typography";

const useStyles = makeStyles(theme => ({
  root: {
    width: 300 + 24 * 2,
    padding: 24
  },
  margin: {
    height: theme.spacing(1)
  }
}));

const PrettoSlider = withStyles({
  root: {
    color: "#a2df77",
    height: 8
  },
  thumb: {
    height: 24,
    width: 24,
    backgroundColor: "#fff",
    border: "2px solid currentColor",
    marginTop: -8,
    marginLeft: -12,
    "&:focus,&:hover,&$active": {
      boxShadow: "inherit"
    }
  },
  active: {},
  valueLabel: {
    left: "calc(-50% + 4px)"
  },
  track: {
    height: 8,
    borderRadius: 4
  },
  rail: {
    height: 8,
    borderRadius: 4
  }
})(Slider);

const CustomSlider = ({ label, value, setValue }) => {
  const classes = useStyles();
  return (
    <Paper className={classes.root}>
      <div className={classes.margin} />
      <Typography gutterBottom>{label}</Typography>
      <PrettoSlider
        valueLabelDisplay="auto"
        aria-label="pretto slider"
        defaultValue={50}
        value={value}
        onChange={(event, v) => {
          setValue(v);
        }}
      />
    </Paper>
  );
};
export default CustomSlider;

Edit Material UI Slider Custom Hook