简体   繁体   English

如何在 Preact 和没有构建工具的情况下使用 useState 钩子?

[英]How to use useState hook with Preact and no build tools?

Currently I need to get a Preact application working without any build tools, just with an index.html with the import statements to get preact from the CDN.目前,我需要让 Preact 应用程序在没有任何构建工具的情况下工作,只需使用带有 import 语句的 index.html 从 CDN 获取 preact。 I'm able to import the useState hook from the CDN no problem, and even able to console.log() the value of the function useState , but whenever I try to use it, I get an error saying:我可以从 CDN 导入useState钩子没有问题,甚至可以 console.log() 函数useState的值,但是每当我尝试使用它时,我都会收到一条错误消息:

'Uncaught TypeError: u is undefined' '未捕获的类型错误:你未定义'

Do ya'll happen to know why this is the case?你会碰巧知道为什么会这样吗? I have tried to use the useState function inside of the functional component, and outside and it doesn't work either way.我尝试在功能组件内部和外部使用useState函数,但无论哪种方式都不起作用。 Am I missing something here?我在这里错过了什么吗? Can anyone help point me in the right direction?谁能帮我指出正确的方向?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="module">
        import { h, Component, render } from 'https://unpkg.com/preact?module';
        import { useState } from 'https://unpkg.com/preact@latest/hooks/dist/hooks.module.js?module'
        import htm from 'https://unpkg.com/htm?module';

        // Initialize htm with Preact
        const html = htm.bind(h);
      
        const App = (props) => {

            const [testVar, setTestVar] = useState(0);

            var countVariable = 0;

            const incrementButtonHandler = () => {
                countVariable = countVariable + 1;
            }

            const logMethod = () => {
                console.log(countVariable);
                countVariable = countVariable + 1;
            }

          return html`<div>
            <h1>Test ${props.name}!: ${countVariable}</h1>
            <button onClick=${logMethod}>Increment</button>
          </div>`;
        }
      
        render(html`<${App} name="World" />`, document.body);
      </script>
</head>
<body>
    
</body>
</html>

This is a known bug and limitation in what unpkg can do, see: https://github.com/preactjs/preact/issues/2571这是 unpkg 可以做的已知错误和限制,请参阅: https ://github.com/preactjs/preact/issues/2571

There's a couple easy fixes though:不过有几个简单的修复方法:

  1. Use already resolved URLs for each module (notice the @latest in the preact import)为每个模块使用已解析的 URL(注意@latest导入中的 @latest)
import { h, render } from 'https://unpkg.com/preact@latest?module'
import { useState } from 'https://unpkg.com/preact@latest/hooks/dist/hooks.module.js?module'
import { html } from 'https://unpkg.com/htm/preact/index.module.js?module'
  1. Use a CDN without this issue, like skypack , instead:使用没有此问题的 CDN,例如skypack
import { h, render } from 'https://cdn.skypack.dev/preact';
import { useState } from 'https://cdn.skypack.dev/preact/hooks';
import { html } from 'https://cdn.skypack.dev/htm/preact';

Either should work.要么应该工作。

rchristian's answer is useful, but the module-imported hooks appear to fail when using a router. rchristian 的回答很有用,但是在使用路由器时,模块导入的钩子似乎失败了。 Here's a minimal repro*.这是一个最小的复制*。

(If you have trouble navigating to the /about route in the snippets, you may need to run them locally since the iframe doesn't play well with routing on all browsers, notably Chrome at the time of writing.) (如果您在导航到代码片段中的/about路由时遇到问题,您可能需要在本地运行它们,因为 iframe 在所有浏览器上都不能很好地支持路由,尤其是在撰写本文时的 Chrome。)

 <script type="module"> import {h, render, Component} from "https://cdn.skypack.dev/preact"; import {useState} from "https://cdn.skypack.dev/preact/hooks"; import {Router} from "https://cdn.skypack.dev/preact-router"; import htm from "https://cdn.skypack.dev/htm"; const html = htm.bind(h); const Counter = () => { const [count, setCount] = useState(0); const increment = () => { setCount(prevState => prevState + 1); }; return html` <button onClick=${increment}> Count: ${count} </button> `; }; const Nav = () => html` <nav> <a href="/">home</a> | <a href="/about">about</a> </nav> `; const Home = () => html` <p>Home</p> <${Counter} /> `; const About = () => html` <p>About</p> `; const App = () => html` <header> <${Nav} /> </header> <main> <${Router}> <${Home} path="/" /> <${About} path="/about" /> <${Home} default /> <//> </main> `; render(html`<${App} />`, document.querySelector("#app")); </script> <div id="app"></div>

Starting at the home route, you'll see the counter component works fine.从主路由开始,您会看到计数器组件工作正常。 Navigate to the about route, then back to home and you'll see Uncaught (in promise) TypeError: u is null from the hooks script.导航到 about 路线,然后返回 home,你会看到Uncaught (in promise) TypeError: u is null from the hooks 脚本。

I'd much prefer the module imports so I'd be curious to hear how to fix the above code, but I did manage to work around this with the following UMD approach:我更喜欢模块导入,所以我很想知道如何修复上述代码,但我确实设法使用以下 UMD 方法解决了这个问题:

 <script type="module"> const {h, render, Component} = preact; const {useState, useEffect} = preactHooks; const {Router} = preactRouter; import htm from "https://cdnjs.cloudflare.com/ajax/libs/htm/3.1.1/htm.module.js"; const html = htm.bind(h); const Counter = () => { const [count, setCount] = useState(0); const increment = () => { setCount(prevState => prevState + 1); }; return html` <button onClick=${increment}> Count: ${count} </button> `; }; const Nav = () => html` <nav> <a href="/">home</a> | <a href="/about">about</a> </nav> `; const Home = () => html` <p>Home</p> <${Counter} /> `; const About = () => html` <p>About</p> `; const App = () => html` <header> <${Nav} /> </header> <main> <${Router}> <${Home} path="/" /> <${About} path="/about" /> <${Home} default /> <//> </main> `; render(html`<${App} />`, document.querySelector("#app")); </script> <script src="https://cdnjs.cloudflare.com/ajax/libs/preact/10.7.2/preact.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/preact/10.7.2/hooks.umd.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/preact-router/4.0.1/preact-router.umd.min.js"></script> <div id="app"></div>

This is similar to Jason Miller's Router example but also uses hooks.这类似于Jason Miller 的路由器示例,但也使用了钩子。


* This is a known issue as developit has a couple of code sandbox repros: * 这是一个已知问题,因为developit 有几个代码沙箱repros:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM