June 3, 2021
By: Tom
Reagent使用react hook
Hook 是 React 16.8 的新增特性. 它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性. 一些第三方库也紧跟变化, 把api改成了Hook的形式. 但是在reagent组件中直接使用hook会报错. 比如:
(require '["react" :as react])
(defn example []
(let [[count set-count] (react/useState 0)]
[:div
[:p "你点击了 " count " 次"]
[:button
{:on-click #(set-count inc)}
"Click"]]))
(defn parent-component []
[:div
[example])
上面的代码运行后会出现下面的报错:
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
React组件分为两种形式, 类组件和函数组件. 而新特性Hooks只能用于函数组件. reagent是把ClojureScript函数转换成了React的类组件(class component). 所以在reagent组件中使用Hooks会抛出错误.
reagent版本在1.0.0之前, 如果要使用Hooks要按照下面方法:
(require '[reagent.core :as r])
(require '["react" :as react])
(defn example []
(let [[count set-count] (react/useState 0)]
;; 使用as-element转成react element
(r/as-element
[:div
[:p "You clicked " count " times"]
[:button
{:on-click #(set-count inc)}
"Click"]])))
(defn reagent-component []
[:div
;; 使用:> 转换
[:> example]])
reagent在1.0.0之后提供了更简洁的方式
(require '["react" :as react])
(defn example []
(let [[count set-count] (react/useState 0)]
[:div
[:p "你点击了 " count " 次"]
[:button
{:on-click #(set-count inc)}
"Click"]]))
(defn reagent-component []
[:div
;; 使用:f> 转为函数组件
[:f> example]])
虽然我们现在可以非常方便的使用React Hook. 但在平时我们自己写组件的时候, 我还是建议用atom, 大部分使用React Hook完成的功能, 使用第二种形式也能完成.
(require '[reagent.core :as r])
(defn example []
(let [count (r/atom 0)]
(fn []
[:div
[:p "你点击了 " @count " 次"]
[:button
{:on-click #(swap! count inc)}
"Click"]])))
(defn parent-component []
[:div
[example])