如何在 React standalone 中使用 React Hooks?

How to use React Hooks in React standalone?

我正在尝试在独立的 UMD 环境中使用 React Hooks。我收到以下错误

Uncaught Invariant Violation: Minified React error #307;

错误将我指向 https://reactjs.org/docs/error-decoder.html/?invariant=307

在这种情况下我该如何使用 Hooks?下面是我的代码:

index.html

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>React Hooks</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="">
    </head>
    <body>
        <!--[if lt IE 7]>
            <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="#">upgrade your browser</a> to improve your experience.</p>
        <![endif]-->
        <div id="root"></div>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
        <script src="App.js" async defer></script>
    </body>
</html>

App.js

var CounterText = function(props) {
    return React.createElement(
        'div',
        null,
        `You clicked ${props.count} times!`
    );
}

var ButtonCounter = function(props) {
    return React.createElement(
        'button',
        {className: 'btn', onClick: props.clickHandler},
        `Click Me!`
    );
}

var Counter = function() {
    var state = React.useState(0);
    var count = state[0];
    var setCount = state[1];

    return React.createElement(
        'div',
        {className: 'counter'},
        CounterText({count: 0}),
        ButtonCounter({})
    );
}

ReactDOM.render(
    Counter(),
    document.getElementById('root')
);

在您的应用中添加 babel standalone。 然后你可以使用 jsx 和所有其他东西,你也需要这样做

<script type="text/babel" src="App.js" async defer></script>

函数式组件如果使用了hooks就不能直接调用了。 createElement 应用于所有组件:

return React.createElement(
    'div',
    {className: 'counter'},
    React.createElement(CounterText, {count: 0}),
    React.createElement(ButtonCounter)
);

您错误地渲染了 Counter 组件,您需要在 ReactDOM.render 中使用 React.createElement 来渲染它。此外,即使您将 ButtonCounter 和 CounterText 传递给 React.createElement like

,该应用程序仍然可以运行
return React.createElement(
    'div',
    {className: 'counter'},
    CounterText({count: count}),
    ButtonCounter({clickHandler: updateCount})
);

最好通过创建其中的 React 元素来传递子元素,以便 React 可以对其进行优化。当 CounterTextButtonCounter 还包含来自 React 的一些逻辑时,这一点尤其重要。

您还可以将状态和处理程序作为工作应用程序的道具传递给这些组件

var CounterText = function(props) {
    return React.createElement(
        'div',
        null,
        `You clicked ${props.count} times!`
    );
}

var ButtonCounter = function(props) {
    return React.createElement(
        'button',
        {className: 'btn', onClick: props.clickHandler},
        `Click Me!`
    );
}

var Counter = function() {
    var state = React.useState(0);
    var count = state[0];
    var setCount = state[1];
    var updateCount = () => {
       setCount(count => count + 1)
    }
    return React.createElement(
        'div',
        {className: 'counter'},
        React.createElement(CounterText, {count: count}),
        React.createElement(ButtonCounter,{clickHandler: updateCount})
    );
}

ReactDOM.render(
    React.createElement(Counter),
    document.getElementById('root')
);
<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>React Hooks</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="">
    </head>
    <body>
        <!--[if lt IE 7]>
            <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="#">upgrade your browser</a> to improve your experience.</p>
        <![endif]-->
        <div id="root"></div>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
        <script src="App.js" async defer></script>
    </body>
</html>

这里有几个问题,你不应该像这样调用你的组件:

Counter()

React 会自己做(惰性求值),所以你也需要用 createElement 包装它。

例如:

ReactDOM.render(
  React.createElement(Counter),
  document.getElementById('root')
);

另一件事,你并没有真正使用 countsetCount

return React.createElement(
        'div',
        {className: 'counter'},
        CounterText({count: 0}),
        ButtonCounter({})
    );

这是一个 运行 示例:

var CounterText = function(props) {
  return React.createElement(
    'div',
    null,
    `You clicked ${props.count} times!`
  );
}

var ButtonCounter = function(props) {
  return React.createElement(
    'button', {
      className: 'btn',
      onClick: props.clickHandler
    },
    `Click Me!`
  );
}

var Counter = function() {
  var state = React.useState(0);
  
  var count = state[0];
  var setCount = state[1];

  return React.createElement(
    'div', {
      className: 'counter'
    },
    React.createElement(CounterText,{
      count:count
    }),
    React.createElement(ButtonCounter,{clickHandler: () => setCount(c => c + 1)})
  );
}

ReactDOM.render(
  React.createElement(Counter),
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
<script src="App.js" async defer></script>