在 React@18 中的类似 Signals 的功能
信號是指
Preact 新增了名为 Signals 的新功能。
介绍信号 – PREACT
预警信号 – PREACT
以下是一种可能的方式,可以更轻松地解决State的桶接力问题,相比于Context等。
import { signal } from "@preact/signals"
const count = signal(0)
const Counter = () => {
const increment = () => {
count.value++
}
return (
<div>
<p>Count: {count.value}</p>
<button onClick={increment}>click me</button>
</div>
)
}
「Signals」在SolidJS中也存在,可以说是最近的趋势。
也许有些人会因为「Signals」而想从React转到Preact或SolidJS。
即使在 React@18 中,模拟信号也可以很容易地实现。
然而,使用 useSyncExternalStore 这个 Hook,我们可以轻松地在 React@18 中实现一个类似于 Signals 的功能,因此,尝试使用它来观察 React 的内部运作方式,可能也是一个不错的选择。
以下是示例代码。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="app"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script>
////////////////////////////////////////////////////
const gV = {}
const signal = iniValue => {
const key = Symbol()
gV[key] = {value: iniValue, fList: new Set()}
return {
get value() {
return gV[key].value
},
set value(newValue) {
if (gV[key].value === newValue) return;
gV[key].value = newValue
gV[key].fList.forEach(f => f())
},
_subscribe: notify => gV[key].fList.add(notify),
_unsubscribe: notify => gV[key].fList.delete(notify),
_remove: () => delete gV[key],
}
}
const useSignal = (...signals) => signals.map(item => React.useSyncExternalStore(
// subscribe
notify => {
item._subscribe(notify)
return () => {
// unsubscribe
item._unsubscribe(notify)
}
},
// getSnapshot
() => item.value,
))
const count1 = signal(0)
const count2 = signal(0)
const Button1 = props => {
useSignal(count1)
return React.createElement('button', {
onClick: e => count1.value++,
}, count1.value)
}
const Button2 = props => {
useSignal(count2)
return React.createElement('button', {
onClick: e => count2.value++,
}, count2.value)
}
const App = props => {
return React.createElement(React.Fragment, {}, [
React.createElement(Button1),
React.createElement(Button1),
React.createElement(Button1),
React.createElement(Button2),
React.createElement(Button2),
React.createElement(Button2),
])
}
const root = ReactDOM.createRoot(document.getElementById("app"))
root.render(React.createElement(App))
////////////////////////////////////////////////////
</script>
</body>
</html>
这里就到现场就完了。
非常感谢您一直陪伴我写下这样拙劣的文章,直到最后。