React -正确触发回调,表示来自React组件的状态更改事件



在一个应用程序中,我正在构建一个自定义范围滑块。我有一个保持当前值的状态,还有一个道具,它公开了在这个内部状态变化时触发的回调。下面是我目前的做法:

const Slider = ({onChange}) => {
const [value, setValue] = useState(0)
// ...
useEffect(() => onChange?.(value), [value, onChange])
// ...
}

这里的问题是onChange是在组件加载时触发的,因为onChange是依赖列表的一部分。但是,如果我从列表中删除这个,它将不会触发更改回调的定义。

这里正确的方法是什么?

  1. 以上是正确的,onChange的订阅者应该考虑到即使实际上没有发生变化,它也会被调用。
  2. onChange在设置值状态的相同函数中触发-但它可以发生在多个地方,我需要确保它在所有所需的地方被调用。

有两个关键点:第一个,OnChange()在这里有两个不同的含义:一个是反馈值的变化,另一个是反馈OnChange()本身的变化。这两者应该分开。第二点是,useEffect()被设计用来对给定的参数执行行为,它的重点是"获得一个新值并做一些事情",比如基于一个新的url数据进行查询。useEffect()实际上是一种设计,它试图基于一些特定的关注点来解耦代码。如果不使用useEffect()来处理业务逻辑,则应该考虑"第一次运行"时代码重复的问题。但是OnChange()关注的是不同的事情。OnChange()本质上高度绑定于setState()。正如您所说,OnChange()应该只关心数据更改,这与useEffect()不同。因此,更好的设计可能不是使用useEffect(),而是包装setState(),并在这个包装的函数中调用OnChange()。如果每次获得关心的值时都有事情要做,请使用useEffect()。函数钩子准备结束最后一个相关值的副作用。useEffect()可以处理每次值改变时要做的事情。

更新答案,这是一个从头开始的功能齐全的滑块。

import {useState} from "react";
const CustomSlider = ({min, max, value, onChange}) => {
const [sliderValue, setSliderValue] = useState(value);
const handleSliderChange = (event) => {
const newValue = parseInt(event.target.value);
setSliderValue(newValue);
onChange(newValue);
}
return (
<div>
<input
type="range"
min={min}
max={max}
value={sliderValue}
onChange={handleSliderChange}
/>
</div>
)
}
export default function App() {
const [value, setValue] = useState(0)
return (
<div>
<CustomSlider
min={0}
max={100}
value={value}
onChange={val => setValue(val)}
/>
{value}
</div>
);
}

要使你的实现工作如你所愿,你需要做两件事:

  1. 防止在第一次渲染时不必要的调用onChange回调,这样你可以检查Slider是否挂载,并且只有在Slider已经挂载的情况下才调用onChange,以下是Slider组件内useEffect所需的更改:
const Slider = ({ onChange }) => {
const [value, setValue] = useState(0)
// ...
const isMounted = useRef(false)
useEffect(() => {
if (isMounted.current === false) {
isMounted.current = true
return
}
onChange?.(value)
return () => {
isMounted.current = false
}
}, [value, onChange])
// ...
}
  1. 确保你传递给Slider组件的onChange回调使用React的useCallback钩子来记忆,它可以防止useEffectSlider组件中不必要的调用,其中onChange回调在依赖列表中由于外部组件的渲染。

相关内容

  • 没有找到相关文章