Если вы хотите создать повторно используемый компонент, всегда старайтесь передать конфигурацию из того места, где он используется, и сохраните все общие конфигурации в стороне от компонента.
EX: Прочитайте, как работают useMemo
и useReducer
useMemo
useReducer
const App = () => {
//Keep slider value in parent
const [parentVal, setParentVal] = useState(10);
//need useCallback why? if this component rendered we don't want to recreate the onChange function
const sliderValueChanged = useCallback(val => {
console.log("NEW VALUE", val);
setParentVal(val);
});
// need useMemo why? if this component rendered we don't want to recreate a new instance of the configuration object,
// but recreate it when parentVal gets changed, so Slider will re-render,
// and you can remove parentVal from dependency array and once the parent parentVal gets updated slider will not be re-renderd
const sliderProps = useMemo(
() => ({
min: 0,
max: 100,
value: parentVal,
step: 2,
label: "This is a reusable slider",
onChange: e => sliderValueChanged(e)
}),
// dependency array, this will call useMemo function only when parentVal gets changed,
// if you 100% confident parentVal only updated from Slider, then you can keep empty dependency array
// and it will not re-render for any configuration object change
[parentVal]
);
return (
<div>
<h1>PARENT VALUE: {parentVal}</h1>
<RangeSlider {...sliderProps} classes="additional-css-classes" />
</div>
);
};
и в компоненте Slider
//destructive props
const RangeSlider = ({ classes, label, onChange, value, ...sliderProps }) => {
//set initial value to 0 this will change inside useEffect in first render also| or you can directly set useState(value)
const [sliderVal, setSliderVal] = useState(0);
// keep mouse state to determine whether i should call parent onChange or not.
// so basically after dragging the slider and then release the mouse then we will call the parent onChange, otherwise parent function will get call each and every change
const [mouseState, setMouseState] = useState(null);
useEffect(() => {
setSliderVal(value); // set new value when value gets changed, even when first render
}, [value]);
const changeCallback = (e) => {
setSliderVal(e.target.value); // update local state of the value when changing
}
useEffect(() => {
if (mouseState === "up") {
onChange(sliderVal)// when mouse is up then call the parent onChange
}
}, [mouseState])
return (
<div className="range-slider">
<p>{label}</p>
<h3>value: { sliderVal }</h3>
<input
type="range"
value={sliderVal}
{...sliderProps}
className={`slider ${classes}`}
id="myRange"
onChange={changeCallback}
onMouseDown={() => setMouseState("down")} // When mouse down set the mouseState to 'down'
onMouseUp={() => setMouseState("up")} // When mouse down set the mouseState to 'up' | now we can call the parent onChnage
/>
</div>
);
};
export default memo(RangeSlider);
посмотрите мою демонстрацию
Я предполагаю, что этот ответ вызывает 3 вопроса
используйте конфигурацию в родительском элементе, чтобы передать нестандартную конфигурацию, например label
Использовать памятку? Да, поэтому компонент Slider будет отображаться только при изменении свойств. Но вы должны тщательно его спроектировать (например, useMemo и useCallback).
steps
? используйте объект конфигурации в родительском элементе, чтобы передать их.
На всякий случай, если вам нужен хороший способ обернуть диапазон, я бы посоветовал вам использовать настраиваемый хук
const useSlider = ({ value, ...config }) => {
const [sliderVal, setSliderVal] = useState(value); // keep a state for each slider
const [configuration, setConfiguration] = useState(config); // keep the configuration for each slider
const onChange = useCallback(val => {
setSliderVal(val);
// useCallback why? we dont need to recreate every time this hook gets called
}, []);
useEffect(() => {
setConfiguration({
...config,
onChange,
value: sliderVal
});
// when sliderVal gets changed call this effect
// and return a new configuration, so the slider can rerender with latest configuration
}, [sliderVal]);
return [sliderVal, configuration];
};
Вот демонстрация
Это может быть дальнейшее улучшение
person
Kalhan.Toress
schedule
04.07.2020