React.js学习-自定义hook-1
2020-09-03 09:23:542020-10-20 16:48:58
自定义hook的好处
可以把组件逻辑抽到可复用的方法里
useRequest
function useRequest<P, T>(api: (params: P) => Promise<T>, params?: P, visiable = true)
:[boolean, T|undefined, (params?: P) => void, () => void] {
const [res, setRes] = useState<T>();
const [loading, setLoading] = useState(() => false);
const [newParams, setNewParams] = useState(() => params);
const [autoFetch, setAutoFetch] = useState(() => visiable);
const fetch = useCallback(async () => {
if (!newParams && autoFetch === false) return;
if (autoFetch) {
const _params = (newParams || {}) as P;
setLoading(true);
const tmp = await api(_params);
setRes(tmp);
setLoading(false);
}
}, [api, autoFetch, newParams]);
useEffect(() => {
fetch();
}, [fetch]);
const doFetch = useCallback((rest = null) => {
setNewParams(rest);
setAutoFetch(true);
}, []);
return [loading, res, doFetch, fetch];
}
useSlider
如果使用传统方式开发,UI界面与逻辑强耦合在一起,若要开发一个横向和一个竖向则代码过于冗余。于是可以使用自定义hook-useSlider
将滑动逻辑复用
// 传统方式开发
import React, { useRef, useEffect, useState } from "react"
const Slider = () => {
const drag = useRef()
const [percent, setPercent] = useState(0)
useEffect(() => {
drag.current.style.left = percent * 300 - 12 + 'px'
}, [percent])
function onMouseDown(e) {
e.persist()
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp)
}
function onMouseMove(e) {
if (e.pageX < 0 || e.pageX > 300) return
setPercent((e.pageX / 300))
drag.current.style.left = e.pageX - 12 + 'px'
}
function onMouseUp() {
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
}
return (
<div>
<div>
<button onClick={() => setPercent(0)}>0</button>
<button onClick={() => setPercent(0.5)}>0.5</button>
<button onClick={() => setPercent(1)}>1</button>
</div>
<p>{ percent }</p>
<div style={{ position: 'relative' }}>
<div style={{ height: '15px', width: '300px', backgroundColor: '#ccc' }}></div>
<div ref={drag} onMouseDown={ onMouseDown } style={{ width: '35px', height: '35px', borderRadius: '50%', position: 'absolute', backgroundColor: '#aaa', top: '-10px', left: 0 }}></div>
</div>
</div>
)
}
export default Slider
// 使用自定义hook开发
// slider2.0.js
import React, { useRef, useEffect, useState } from "react"
const useSlider = ({ dragWidth, slideWidth, direction ='horizontal' }) => {
const drag = useRef()
const [percent, setPercent] = useState(0)
const [originPosition, setOriginPosition] = useState(() => ({ x: 0 ,y: 0 }))
useEffect(() => {
if (direction === 'horizontal') drag.current.style.left = percent * slideWidth - (dragWidth>>1) + 'px'
else drag.current.style.top = percent * slideWidth - (dragWidth>>1) + 'px'
}, [percent])
useEffect(() => {
const { left, top } = drag.current.getBoundingClientRect()
setOriginPosition({ x: left, y: top })
return onMouseUp
}, [drag])
function onMouseDown() {
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp)
}
function onMouseMove(e) {
if (direction === 'horizontal') {
const pos = e.pageX - originPosition.x - (dragWidth>>1)
if (pos < 0 || pos > slideWidth) return
setPercent(pos / slideWidth)
drag.current.style.left = pos - (dragWidth>>1) + 'px'
} else {
const pos = e.pageY - originPosition.y - (dragWidth>>1)
if (pos < 0 || pos > slideWidth) return
setPercent(pos / slideWidth)
drag.current.style.top = pos - (dragWidth>>1) + 'px'
}
}
function onMouseUp() {
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
}
return [
drag,
percent,
onMouseDown,
setPercent
]
}
const Slider = () => {
const [ dragH, percentH, onDragMouseDownH, setPercentH ] = useSlider({ dragWidth: 35, slideWidth: 300 })
const [ dragV, percentV, onDragMouseDownV, setPercentV ] = useSlider({ dragWidth: 35, slideWidth: 300, direction: 'vertical' })
return (
<>
{/* 可以分别创建一个SliderV.js和SliderH.js */}
<div style={{ marginLeft: '20px' }}>
<p>横向</p>
<div>
<button onClick={() => setPercentH(0)}>0</button>
<button onClick={() => setPercentH(0.5)}>0.5</button>
<button onClick={() => setPercentH(1)}>1</button>
</div>
<p>{ percentH }</p>
<div style={{ position: 'relative' }}>
<div style={{ height: '15px', width: '300px', backgroundColor: '#ccc' }}></div>
<div style={{ width: `${percentH * 300}px`, height: '15px', position: 'absolute', top: '0', backgroundColor: '#f00' }}></div>
<div ref={dragH} onMouseDown={onDragMouseDownH} style={{ width: '35px', height: '35px', borderRadius: '50%', position: 'absolute', backgroundColor: '#aaa', left: 0, top: '-10px' }}></div>
</div>
</div>
<div style={{ marginLeft: '20px' }}>
<p>竖向</p>
<div>
<button onClick={() => setPercentV(0)}>0</button>
<button onClick={() => setPercentV(0.5)}>0.5</button>
<button onClick={() => setPercentV(1)}>1</button>
</div>
<p>{ percentV }</p>
<div style={{ position: 'relative' }}>
<div style={{ height: '300px', width: '15px', backgroundColor: '#ccc' }}></div>
<div style={{ height: `${percentV * 300}px`, width: '15px', position: 'absolute', left: '0', top: '0', backgroundColor: '#f00' }}></div>
<div ref={dragV} onMouseDown={onDragMouseDownV} style={{ width: '35px', height: '35px', borderRadius: '50%', position: 'absolute', backgroundColor: '#aaa', top: 0, left: '-10px' }}></div>
</div>
</div>
</>
)
}
export default Slider