Jas*_*ngh 1 onclick typescript reactjs next.js react-hooks
我正在尝试在 NextJS 应用程序中播放音频,并且正在使用 TypeScript 编写代码。当我这样做时,我onClick()在开发环境中工作得非常好npm run dev。
<button onClick ={toggle}> {playing ? "Pause" : "Play"</button>
Run Code Online (Sandbox Code Playgroud)
但是当我尝试这样做时,npm build我收到此错误:
类型错误:输入“布尔值|” (() => void)' 不可分配给类型 'MouseEventHandler | 不明确的'。类型“false”不可分配给类型“MouseEventHandler |” 不明确的'。
在阅读了 Stack Overflow 上的一系列问题后,我发现onClick()不需要一个 void,这就是toggle在这种情况下返回的函数,所以我这样做了:
<button onClick={() => toggle}> {playing ? "Pause" :"Play</button>
Run Code Online (Sandbox Code Playgroud)
经过上述更改后,分配错误消失了,但是当我运行应用程序时,播放按钮不再起作用。我愿意接受您对代码的任何其他建议。
这是完整的代码:
const useAudio = (url: string) => {
const audio = useRef<HTMLAudioElement | undefined>(
typeof Audio !== "undefined" ? new Audio(url) : undefined
);
const [playing, setPlaying] = useState(false);
const toggle = () => setPlaying(!playing);
//const toggle = setPlaying(!playing);
useEffect(() => {
playing ? audio.current?.play() : audio.current?.pause();
}, [playing]);
useEffect(() => {
audio.current?.addEventListener('ended', () => setPlaying(false));
return () => {
audio.current?.removeEventListener('ended', () => setPlaying(false));
};
}, []);
return [playing, toggle];
};
const NFT = ({ baseUri, metaId, url }: { baseUri: string; metaId: string; url: string }) => {
const [metadata, setMetadata] = useState<{[key: string]: string} | null>(null)
const fetchMetadata = async (url: string) => {
const response = await fetch(url)
const result = await response.json()
if (!result) return
setMetadata(result)
}
if(url) {
var [playing, toggle] = useAudio(url);
}
useEffect(() => {
fetchMetadata(`${baseUri}/${metaId}`)
}, [])
if (!metadata) return null
return (
<div className="w-full md:w-1/2 lg:w-1/3 p-3 mb-4">
<div className="h-96">
<div className="relative items-center min-h-full">
<a href="#">
<Image
alt={metadata[MetadataField.Title]}
src={metadata[MetadataField.Media]}
layout="fill"
objectFit="contain"
/>
</a>
</div>
{url &&
<button onClick ={toggle}> {playing ? "Pause" : "Play"} </button>
}
</div>
</div>
)
}
Run Code Online (Sandbox Code Playgroud)
来自反应打字稿备忘单
如果您在自定义 Hook 中返回一个数组,您将需要避免类型推断,因为 TypeScript 将推断联合类型(当您实际上希望数组的每个位置有不同的类型时)。
您需要使用const 断言
const useAudio = (url: string) => {
const audio = useRef<HTMLAudioElement | undefined>(typeof Audio !== 'undefined' ? new Audio(url) : undefined);
const [playing, setPlaying] = useState(false);
const toggle = () => setPlaying(!playing);
useEffect(() => {
playing ? audio.current?.play() : audio.current?.pause();
}, [playing]);
useEffect(() => {
audio.current?.addEventListener('ended', () => setPlaying(false));
return () => {
audio.current?.removeEventListener('ended', () => setPlaying(false));
};
}, []);
return [playing, toggle] as const;
};
Run Code Online (Sandbox Code Playgroud)
请参见下面的示例:
function test() {
return [true, () => {}];
}
const [isOk, func] = test();
func(); // error
Run Code Online (Sandbox Code Playgroud)
函数的返回类型是TypeScript 推断的test联合类型。(boolean | (() => void))[]当你调用时func(),你会得到错误:
This expression is not callable.
Not all constituents of type 'boolean | (() => void)' are callable.
Type 'false' has no call signatures.ts(2349)
Run Code Online (Sandbox Code Playgroud)
解决方案1:const assertions
function test() {
return [true, () => {}] as const
}
Run Code Online (Sandbox Code Playgroud)
这将推断出[boolean, () => void]而不是(boolean | (() => void))[]
test解决方案2:显式声明返回类型
function test(): [boolean, () => void] {
return [true, () => {}];
}
Run Code Online (Sandbox Code Playgroud)
此外,你不能有条件地使用钩子,它违反了钩子规则
| 归档时间: |
|
| 查看次数: |
4515 次 |
| 最近记录: |