svelte 中的反应性减速未按预期工作
Reactive deceleration in svelte not working as expected
我正在尝试创建一个 TextAreaAutosize 组件,其中 returns 一个可在需要时自动调整高度的文本区域。
我想在高度变化时 运行 onHeightChange 函数,所以我使用了精巧的反应语句($:),这样每当高度变化时,那段代码 运行。
App.svelte
<script>
import TextArea from "./TextAreaAutosize.svelte";
let val, ref;
</script>
<TextArea
bind:value={val}
bind:ref={ref}
style={"height: 90px; maxHeight=40"}
minRows={4}
/>
TextAreaAutosize.svelte
<script context="module">
import calculateNodeHeight from './calculateNodeHeight.js'
let uid = 0;
const noop = () => {};
</script>
<script>
export let value = '';
export let style;
export let useCacheForDOMMeasurements = false;
export let minRows = -Infinity;
export let maxRows = +Infinity;
export let onHeightChange = noop;
export let ref = null;
let refConfig = {
_uid: uid++
}
let state = {
height: 0,
minHeight: -Infinity,
maxHeight: +Infinity
}
// runs when change in height
$: if(state.height){
//block 1
console.log('height changed')
onHeightChange(refConfig)
}
// resizes element on initial mount or whenever change in value
$:if(ref || value){
//block 2
_resizeComponent()
}
// function for resizing textarea when required
function _resizeComponent(){
if(!ref){
return;
}
const refHeight = calculateNodeHeight(
ref,
refConfig._uid,
useCacheForDOMMeasurements,
minRows,
maxRows
);
const {
height,
minHeight,
maxHeight,
rowCount,
valueRowCount
} = refHeight;
refConfig.rowCount = rowCount;
refConfig.valueRowCount = rowCount;
if(
state.height !== height ||
state.maxHeight !== maxHeight ||
state.minHeight !== minHeight
){
state = {height, minHeight, maxHeight}
}
}
</script>
<textarea
bind:value={value}
bind:this={ref}
style={`${style};height: ${state.height}px;`}
on:click
on:change
class={$$props.class}
/>
在此组件中,只要 state.height 发生变化,块 1 就应该 运行。但它根本没有 运行。但是,当我将它放在 block2 之后时,只要 state.height
发生变化,它就会 运行s
当 textarea 的值更改 block2 运行 并调用 _resizeComponent,然后根据需要用新的高度更新状态。如果高度改变,它应该触发 block1。但只有当我把它放在 block2
之后它才会触发那个块
我无法理解为什么我的代码会出现这种行为。块 1 中的语句应该 运行 每当 state.height 发生变化时,无论反应语句的顺序如何
Svelte 无法通过分析该代码确定第二个块是否会影响 state
的值。所以它不会首先将块重新排序为 运行 第二个。 (它不能只保留 re-running 反应块,如果最后有意想不到的变化;那是无限循环。)
如果不只是 _resizeComponent()
而是 state = _resizeComponent()
,并且相应地更改函数,那将会改变。或者,只需手动重新排序块。
顺便说一句,有一个更简单的方法来获得 auto-resizing 文本区域:https://svelte.dev/repl/40f4c7846e6f4052927ff5f9c5271b66?version=3.6.8
我正在尝试创建一个 TextAreaAutosize 组件,其中 returns 一个可在需要时自动调整高度的文本区域。
我想在高度变化时 运行 onHeightChange 函数,所以我使用了精巧的反应语句($:),这样每当高度变化时,那段代码 运行。
App.svelte
<script>
import TextArea from "./TextAreaAutosize.svelte";
let val, ref;
</script>
<TextArea
bind:value={val}
bind:ref={ref}
style={"height: 90px; maxHeight=40"}
minRows={4}
/>
TextAreaAutosize.svelte
<script context="module">
import calculateNodeHeight from './calculateNodeHeight.js'
let uid = 0;
const noop = () => {};
</script>
<script>
export let value = '';
export let style;
export let useCacheForDOMMeasurements = false;
export let minRows = -Infinity;
export let maxRows = +Infinity;
export let onHeightChange = noop;
export let ref = null;
let refConfig = {
_uid: uid++
}
let state = {
height: 0,
minHeight: -Infinity,
maxHeight: +Infinity
}
// runs when change in height
$: if(state.height){
//block 1
console.log('height changed')
onHeightChange(refConfig)
}
// resizes element on initial mount or whenever change in value
$:if(ref || value){
//block 2
_resizeComponent()
}
// function for resizing textarea when required
function _resizeComponent(){
if(!ref){
return;
}
const refHeight = calculateNodeHeight(
ref,
refConfig._uid,
useCacheForDOMMeasurements,
minRows,
maxRows
);
const {
height,
minHeight,
maxHeight,
rowCount,
valueRowCount
} = refHeight;
refConfig.rowCount = rowCount;
refConfig.valueRowCount = rowCount;
if(
state.height !== height ||
state.maxHeight !== maxHeight ||
state.minHeight !== minHeight
){
state = {height, minHeight, maxHeight}
}
}
</script>
<textarea
bind:value={value}
bind:this={ref}
style={`${style};height: ${state.height}px;`}
on:click
on:change
class={$$props.class}
/>
在此组件中,只要 state.height 发生变化,块 1 就应该 运行。但它根本没有 运行。但是,当我将它放在 block2 之后时,只要 state.height
发生变化,它就会 运行s当 textarea 的值更改 block2 运行 并调用 _resizeComponent,然后根据需要用新的高度更新状态。如果高度改变,它应该触发 block1。但只有当我把它放在 block2
之后它才会触发那个块我无法理解为什么我的代码会出现这种行为。块 1 中的语句应该 运行 每当 state.height 发生变化时,无论反应语句的顺序如何
Svelte 无法通过分析该代码确定第二个块是否会影响 state
的值。所以它不会首先将块重新排序为 运行 第二个。 (它不能只保留 re-running 反应块,如果最后有意想不到的变化;那是无限循环。)
如果不只是 _resizeComponent()
而是 state = _resizeComponent()
,并且相应地更改函数,那将会改变。或者,只需手动重新排序块。
顺便说一句,有一个更简单的方法来获得 auto-resizing 文本区域:https://svelte.dev/repl/40f4c7846e6f4052927ff5f9c5271b66?version=3.6.8