Open into-piece opened 3 years ago
import {
useCallback,
useEffect,
useRef,
useState,
MutableRefObject,
} from 'react';
import Sound from 'react-native-sound';
import { downLoadFile } from '@/utils/utils';
type Status = 'pause' | 'play' | 'pending';
export const statusMap: Record<'PAUSE' | 'PLAY' | 'PENDING', Status> = {
PAUSE: 'pause',
PLAY: 'play',
PENDING: 'pending',
};
export type SoundMethods = {
play: (callback: (error: Error) => void) => void;
pause: () => void;
};
export type Info = {
status: Status;
currentTime: number;
duration: number;
};
const useSound = (
url: string
): [SoundMethods, Info, MutableRefObject<Sound | null>] => {
const soundRef = useRef<Sound | null>(null);
const timer = useRef<any>(null);
const [status, setStatus] = useState(statusMap.PAUSE);
const [currentTime, setCurrentTime] = useState(0);
const [error, setError] = useState('');
const [duration, setDuration] = useState(0);
const play = useCallback(
(callback) => {
setStatus(statusMap.PLAY);
soundRef.current?.play((success) => {
if (success) {
clearInterval(timer.current);
setStatus(statusMap.PAUSE);
setCurrentTime(duration);
}
});
callback(error);
},
[error, duration]
);
const pause = useCallback(() => {
soundRef.current?.pause();
setStatus(statusMap.PAUSE);
}, []);
useEffect(() => {
if (status === statusMap.PLAY) {
timer.current = setInterval(() => {
soundRef.current?.getCurrentTime((second) => {
setCurrentTime(second);
});
}, 1000);
}
return () => {
clearInterval(timer.current);
};
}, [status, soundRef]);
useEffect(() => {
if (!url) {
return;
}
setStatus(statusMap.PENDING);
const { savePath, rnfs } = downLoadFile(url);
rnfs.promise
.then((res) => {
if (res.statusCode === 200) {
soundRef.current = new Sound(savePath, '', (err) => {
if (err) {
setError(err);
return;
}
setDuration(soundRef.current?.getDuration()!);
});
setStatus(statusMap.PAUSE);
}
})
.catch((err) => {
setError(err);
});
return () => {
soundRef.current?.release();
};
}, [url]);
return [
{ play, pause },
{
status,
currentTime,
duration,
},
soundRef,
];
};
export default useSound;
hooks中传入传出api的设计 比如我们rn app需要引入录音功能,确认需要引入一个react-native-sound库, 根据这个库的pai 我们自己设计一个useSound的hook,因为他本身没有提供对应的hooks 需要有什么功能,点击play方法,pause方法,录音的duration属性,播放时长做一个进度条, 我们需要考虑传入传出,传入先传一个考虑录音的url, 尽量少的回调函数的传入,比如我想在报错的时候进行提示,这种我们是不会在hooks里面直接提示的,但按以前我开发的思路,可能会传一个处理error的回调函数进去,会想到再useCallback一下,嗯,觉得很完美,但是其实hooks只是来帮你管理状态的,越多的回调的传入反而让hook显示臃肿,更优化的方法是先用一个useState新增一个error,来捕获存储代码过程中的报错,最后将之抛出。
这里获取error的设计,我是在自定义的play方法中接受第二个参数,进行return err,这样子