编写一个设置当前进度的自定义钩子:React hooks

问题描述 投票:0回答:2

我有一个进度条,单击它即可从 60 开始进度,一直到 100。我可以使用 settinterval 并设置相应的状态来实现此目的。

import React, { useState, useRef } from "react";
import ProgressBar from "./ProgressBar";

export default function App() {
  const [file, setFile] = useState({ status: 0, error: "" });
  const mockRef = useRef(60);

  const initiate = () => {
    const intervalID = setInterval(() => {
      if (mockRef.current >= 100) {
        clearInterval(intervalID);
        setFile((prevState) => ({
          ...prevState,
          status: 100
        }));
      } else {
        setFile((prevState) => ({
          ...prevState,
          status: mockRef.current
        }));
        mockRef.current = mockRef.current + 10;
      }
    }, 200);
  };

  return (
    <div className="App" style={appStyles}>
      <button type="button" onClick={initiate}>
        Click Me!
      </button>
      <ProgressBar bgColor={"#DF8100"} progress={file.status} />
      {file.status === 100 && <span>Upload complete</span>}
    </div>
  );
}

我使用 ref 将进度动态增加 10,当进度达到 100 时,我将其清除并将消息显示为

Upload Complete
。代码运行得很好。

沙箱:https://codesandbox.io/s/simple-react-progress-bar-forked-yfz9xb?file=/src/useProgress.jsx:0-436

现在我希望

initiate
内部的内容将其移动到自定义挂钩,该挂钩应该处理 setinterval 功能并设置对象,以便功能保持不变。可能这个 cutsom 钩子应该以初始百分比作为数字,并且可能是状态设置器。

知道如何编写这个自定义钩子。这就是我的尝试

import { useRef } from "react";

export const useProgress = (state, timer) => {
  const mockRef = useRef(timer);

  const intervalID = setInterval(() => {
    if (mockRef.current >= 100) {
      clearInterval(intervalID);
      return {
        ...state,
        status: 100
      };
    } else {
      mockRef.current = mockRef.current + 10;
      return {
        ...state,
        status: mockRef.current
      };
    }
  }, 200);
};
javascript reactjs react-hooks setinterval
2个回答
2
投票

当您在函数组件中运行某些内容并希望将其变成钩子时,这通常比人们想象的要容易。通常,您可以将功能代码直接复制到钩子中;使钩子接受代码外部所需的任何内容作为参数;并从钩子中返回调用组件所需的任何内容作为返回值(如果有多个值,请将它们包装在数组[元组]或对象中)。

在您的情况下,只需将组件中

return
之前的所有内容复制到挂钩中,然后让挂钩返回
file
initiate
:

export const useProgress = () => {
    const [file, setFile] = useState({ status: 0, error: "" });
    const mockRef = useRef(60);

    const initiate = () => {
        const intervalID = setInterval(() => {
            if (mockRef.current >= 100) {
                clearInterval(intervalID);
                setFile((prevState) => ({
                    ...prevState,
                    status: 100,
                }));
            } else {
                setFile((prevState) => ({
                    ...prevState,
                    status: mockRef.current,
                }));
                mockRef.current = mockRef.current + 10;
            }
        }, 200);
    };

    return [file, initiate];
};

然后

App
这样使用它:

export default function App() {
    const [file, initiate] = useProgress();

    return (
        <div className="App" style={appStyles}>
            <button type="button" onClick={initiate}>
                Click Me!
            </button>
            <ProgressBar bgColor={"#DF8100"} progress={file.status} />
            {file.status === 100 && <span>Upload complete</span>}
        </div>
    );
}

更新了沙箱


1
投票

您可以提供

updater
处理函数和
timer
起始值作为参数,这些参数可以根据您使用自定义挂钩的位置而变化。

这也可以:

import { useRef } from "react";

const useProgress = (updater, timer) => {
  const mockRef = useRef(timer);

  const initiate = () => {
    const intervalID = setInterval(() => {
      if (mockRef.current >= 100) {
        clearInterval(intervalID);
        updater((prevState) => ({
          ...prevState,
          status: 100
        }));
      } else {
        mockRef.current = mockRef.current + 10;
        updater((prevState) => ({
          ...prevState,
          status: mockRef.current
        }));
      }
    }, 200);
  };

  return initiate;
};

export default useProgress;

在你的

App.jsx

...
...
export default function App() {
  const [file, setFile] = useState({ status: 0, error: "" });
  const initiate = useProgress(setFile, 60);

  return (
    <div className="App" style={appStyles}>
      <button type="button" onClick={initiate}>
        Click Me!
      </button>
      <ProgressBar bgColor={"#DF8100"} progress={file.status} />
      {file.status === 100 && <span>Upload complete</span>}
    </div>
  );
}
...

Codesandbox 演示:

Edit simple react progress bar (forked)

如果状态是一个数组,那么

fileIndex
可以传递到自定义钩子中:

Edit simple react progress bar (forked)

© www.soinside.com 2019 - 2024. All rights reserved.