Open Clonkex opened 7 months ago
I've run into the same issue just now. Did you ever found a solution/workaround @Clonkex ?
@Aidenir Unfortunately my "solution" was to switch to Preact + HTM (which is relatively easy to achieve even with an existing ArrowJS codebase because the ArrowJS and HTM syntax is similar - it's also still fully clientside, no build step necessary). It's not quite as elegant as ArrowJS in some ways (in particular, it took me a while to get my head around state handling - having to set an entirely new copy of the object when anything changes feels jank, but also potentially simpler and more reliable) but in other ways it's simpler and has the significant benefit of being battle-tested. If you make the same switch, just know that when you're trying to understand some Preact feature, search for React first because Preact is basically just a reimplementation of React.
So yeah, I was unable to work around this problem and it was enough to make me suffer the pain of learning Preact instead.
Alright, thanks for the reply @Clonkex :) . I did find a super janky workaround I think, where I changed the type of the value I keep in the reactive state to a string instead of an array: https://jsfiddle.net/09Lwopqy/
function getLoginComponent() {
const state = reactive({
pageDatas: "[]",
});
setTimeout(async () => {
state.pageDatas = JSON.stringify(JSON.parse(state.pageDatas).push(Date.now()))
}, 500);
return html`<div>bob</div>`;
}
From limited testing this at least solved my issue for now, and while it's definitely not a good solution, it let me keep working on the other problems in my app until hopefully a better solution comes along :P
Alright, thanks for the reply @Clonkex :) . I did find a super janky workaround I think, where I changed the type of the value I keep in the reactive state to a string instead of an array: https://jsfiddle.net/09Lwopqy/
function getLoginComponent() { const state = reactive({ pageDatas: "[]", }); setTimeout(async () => { state.pageDatas = JSON.stringify(JSON.parse(state.pageDatas).push(Date.now())) }, 500); return html`<div>bob</div>`; }
From limited testing this at least solved my issue for now, and while it's definitely not a good solution, it let me keep working on the other problems in my app until hopefully a better solution comes along :P
There are things wrong with this code and the code above it:
setTimeout
doesn't take awaitable functions, remove the async in front of the lambdareactive
variable to an object that has one property pageDatas
, just use the array directly and it should work fineTry this: const pageTimestamp = reactive([])
Then you should be able to use it like this: pageTimestamp.push(Date.now())
Also, the naming of the variable to state
doesn't describe what you are using it for and pageDatas
is also poorly named as it looks to be timestamps. If you need to keep state
then you would need to spread the array, as only the object changes are being tracked, so changing the child array directly will never trigger the change event.
Here is how keeping the object would work: state.pageTimestamps = [...state.pageTimestamps, Date.now()]
Please note that using the object will cause additional rerendering if any other properties are attached to that object. That is why I first recommended making the array reactive.
@jfftck You're reading too much into my testing code haha. It was cut down from real code and I didn't rename some things.
setTimeout
doesn't take awaitable functions, remove the async in front of the lambda
Well in my original code the lambda await
ed some stuff, which is why the async
is there. I just forgot to remove it. It also makes no difference to setTimeout
whether the function is awaitable or not; if the lambda await
s anything it needs to be marked as async
.
You shouldn't set your
reactive
variable to an object that has one propertypageDatas
, just use the array directly and it should work fine
It's been a while, but I believe I tried this and it made no difference. Or maybe it did make a difference but I couldn't do that because my real state was more complex and had multiple fields.
But your problem of circular loop can be fixed by splitting your state, anything that is for the component directly should be separate from the state for the children. Having it as 1 shared state can cause any changes to rerender both components.
This one is quite confusing. I'm not sure if I'm doing something wrong or if it's a bug in ArrowJS.
This is as simple as I can make it while still replicating the behaviour:
https://jsfiddle.net/9d51qhe2
If you run the fiddle, you'll see it continually prints
zz0mkno
. It's re-rendering the entiregetLoginComponent
component every time in an infinite loop.Here's a fiddle that demonstrates more closely what I was doing when I came across this bug (including a network request instead of a timeout). Basically I was loading some user data on the login page to allow it to do client-side validation before making a server request to log in.