Comments (9)
Thanks for reporting,
In your code, the closure on the onclick
function is capturing a value usize vc
at the time the onclick is assigned to the actual event listener in js
code and then this fix value is always passed to the Msg::Click
enum variant. What you may need to do is to load again the value from VIEW_COUNT
each time the button is clicked. So it will be reading from the actual source, rather than a snapshot at which the closure is constructed and assigned to the event listener.
Here is the modified view of the code, which works as they way you wanted.
fn view(&self) -> Node<Msg> {
div(
[],
[
div(
[],
[input(
[
r#type("button"),
value(format!("VIEW_COUNT: {}",self.number)),
onclick(move |_| {
VIEW_COUNT.fetch_add(1, Ordering::SeqCst);
let vc = VIEW_COUNT.load(Ordering::SeqCst);
sauron::log(format!("Button is clicked (VIEW_COUNT = {})", vc));
Msg::Click(vc)
}),
],
[],
)],
),
div(
[],
[text(format!(
"VIEW_COUNT: {}",
VIEW_COUNT.load(Ordering::SeqCst)
))],
),
div(
[],
[text(format!(
"number: {}",
self.number
))],
),
],
)
}
from sauron.
Thanks for the response.
Although the proposed solution works in this particular case, I don't think that it generalises to the actual problem I'm trying to solve. In my particular case, I need the onclick
behaviour to depend on the application state at the time that view
is called (i.e. when the closure is created). That's the situation I tried to recreate in this example. In your proposal, the onclick
behaviour depends on the application state at the time that the closure is called (as opposed to when it is created).
The originally observed behaviour, therefore, still surprises me.
Inside view
, the vc
variable appears in two places in the button's state: it controls the value
and it controls the onclick
behaviour. The value updates with each view
invocation. However, the onclick
behaviour always stays the same (for a particular button) between view
invocations (each with a different value of vc
).
Relevant snippet as follows:
[input(
[
r#type("button"),
value(format!("VIEW_COUNT: {}", vc)),
onclick(move |_| {
sauron::log(format!("Button is clicked (VIEW_COUNT = {})", vc));
Msg::Click(vc)
}),
],
[],
)],
from sauron.
That's the behavior of the framework for optimization reason. The event listener is attached only one time at the time it is created and is never replaced even with a different closure/function, as there is no easy way to compare closure if they have changed or not. The attributes(ie: value
) however changed since there is no performance penalty to keep changing these values at every re-render of the DOM.
Maybe you could also passed the VIEW_COUNT
to the Msg::Click
directly and read the value in the update
call.
from sauron.
Thanks. The behaviour now makes sense.
What now does not make sense is why your example todomvc
app works. Specifically, in view_entry
, you register a number of onclick
handlers which depend on the item index, idx
. The value of idx
for a particular item can differ between different view
invocations (e.g. when the item at the top of the list is removed). However, for some reason these closures are recreated with the correct idx
value after each view
invocation. For example, https://github.com/ivanceras/sauron/blob/master/examples/todomvc/src/app.rs#L267:
input(
[
class("toggle"),
r#type("checkbox"),
checked(entry.completed),
onclick(move |_| Msg::Toggle(idx)),
],
[],
),
from sauron.
It works beacuase idx is a usize
, which is a Copy
type, everytime it is passed around, it will be copy of a new usize
. However, you can not apply the same for AtomicUsize
, since these are a bit complex types in rust. Simple types such as the primitives: u8,f32,u64,usize
, etc, is easy to work on and works as expected while using clean code.
from sauron.
The vc
value used in the closure is not an AtomicUsize
, but a usize
(it's loaded as a usize
at the top of view
): https://github.com/gesterhuizen/sauron-onclick/blob/master/src/lib.rs#L31
let vc : usize = VIEW_COUNT.load(Ordering::SeqCst);
from sauron.
I'm closing this issue now, since this not going anywhere, and is not related to sauron
in particular but with how you are seeing rust types. If you need more answers about closures and atomics please use the rust-users or /r/rust forums.
from sauron.
Not trying to be annoying, but a port of the same code to Yew seems to work just fine: https://github.com/gesterhuizen/yew-onclick
I'm really just trying to understand what I'm doing wrong here and what I'm missing. Unfortunately, the explanations given above does not make sense to me (and the issue does not seem fundamentally tied to the way I'm using an atomic).
from sauron.
I realized that the root cause of this issue is caused from using Fn
inside the Callback
instead of FnMut
as it is easier to deal with Fn
not having to passed arround a lot of mutable reference to Callback
. The purpose of event callbacks in the nodes should only be limited to passing what kind of Msg
to process, anything complicated should be done in the update
method which has access to a mutable reference of the App
.
from sauron.
Related Issues (20)
- node!(<h1>"example"</h1>) syntax does not work on released version 0.32.4 HOT 3
- Error: Window is not defined [Cloudflare Worker] HOT 1
- Interval / timeout / any way to execute something in background HOT 1
- Community HOT 1
- svg tags not showing when using node! macro in the client HOT 2
- How does sauron compare to seed? HOT 2
- input disabled attribute had different behavior that I was expecting in node macro HOT 3
- nodes inserted at position 0 have broken events HOT 6
- Correctly set value of HtmlOptionElement HOT 1
- windows-tab-rows demo lags HOT 2
- Closures attached to similar nodes misbehave HOT 2
- FYI: js-framework-benchmark
- How to get a node ref? HOT 1
- Panicking when using `node! {}` or `fragment([])` HOT 1
- Adding items to a list causes unexpected duplication, and more panics HOT 1
- Updates to attributes of parent of node with "key" are ignored HOT 1
- Moving to syn-rsx fork HOT 2
- Component initialisation HOT 1
- Input box value not correctly cleared&rerendered starting from tag 400ms (including all 0.61.0 onward) HOT 2
- Avoid top lvl await in page init
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sauron.