Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

组件封装思路 #40

Open
into-piece opened this issue Apr 25, 2021 · 1 comment
Open

组件封装思路 #40

into-piece opened this issue Apr 25, 2021 · 1 comment

Comments

@into-piece
Copy link
Owner

into-piece commented Apr 25, 2021

hooks中传入传出api的设计
比如我们rn app需要引入录音功能,确认需要引入一个react-native-sound库,
根据这个库的pai 我们自己设计一个useSound的hook,因为他本身没有提供对应的hooks
需要有什么功能,点击play方法,pause方法,录音的duration属性,播放时长做一个进度条,
我们需要考虑传入传出,传入先传一个考虑录音的url,
尽量少的回调函数的传入,比如我想在报错的时候进行提示,这种我们是不会在hooks里面直接提示的,但按以前我开发的思路,可能会传一个处理error的回调函数进去,会想到再useCallback一下,嗯,觉得很完美,但是其实hooks只是来帮你管理状态的,越多的回调的传入反而让hook显示臃肿,更优化的方法是先用一个useState新增一个error,来捕获存储代码过程中的报错,最后将之抛出。

  1. error callback 回调作为参数传入
  2. 在对应调用方法如play方法中传入错误回调作为参数执行,将error传入
  3. play方法中return一个promise

这里获取error的设计,我是在自定义的play方法中接受第二个参数,进行return err,这样子

@into-piece into-piece changed the title 组件封装 组件封装思路 Apr 25, 2021
@into-piece
Copy link
Owner Author

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;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant