Skip to content

Commit b68e914

Browse files
authored
fix: Avoid data race in query subscription by making mutation creation synchronous in use_mutation (#49)
* fix: Avoid data race in query subscription by making mutation creation synchronous in `use_mutation` * chore: Clean up Query code
1 parent bfd76bf commit b68e914

File tree

3 files changed

+30
-32
lines changed

3 files changed

+30
-32
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "dioxus-query"
33
description = "Fully-typed, async, reusable cached state management for Dioxus 🧬"
4-
version = "0.9.1"
4+
version = "0.9.2"
55
edition = "2021"
66
license = "MIT"
77
authors = ["Marc Espín <[email protected]>"]

src/mutation.rs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use core::fmt;
22
use dioxus::prelude::*;
3-
use dioxus::{
4-
hooks::{use_memo, use_reactive},
5-
signals::CopyValue,
6-
};
3+
use dioxus::signals::CopyValue;
74
use dioxus_core::{provide_root_context, spawn_forever, use_drop, ReactiveContext, Task};
85
use std::{
96
cell::{Ref, RefCell},
@@ -262,7 +259,7 @@ impl<Q: MutationCapability> MutationReader<Q> {
262259
}
263260

264261
pub struct UseMutation<Q: MutationCapability> {
265-
mutation: Memo<Mutation<Q>>,
262+
mutation: Signal<Mutation<Q>>,
266263
}
267264

268265
impl<Q: MutationCapability> Clone for UseMutation<Q> {
@@ -370,29 +367,33 @@ pub fn use_mutation<Q: MutationCapability>(mutation: Mutation<Q>) -> UseMutation
370367
None => provide_root_context(MutationsStorage::<Q>::new_in_root()),
371368
};
372369

373-
let current_mutation = use_hook(|| Rc::new(RefCell::new(None)));
374-
375-
// Create or update mutation subscription on changes
376-
let mutation = use_memo(use_reactive!(|mutation| {
370+
let mut make_mutation = |mutation: &Mutation<Q>, mut prev_mutation: Option<Mutation<Q>>| {
377371
let _data = storage.insert_or_get_mutation(mutation.clone());
378372

379373
// Update the mutation tasks if there has been a change in the mutation
380-
if let Some(prev_mutation) = current_mutation.borrow_mut().take() {
374+
if let Some(prev_mutation) = prev_mutation.take() {
381375
storage.update_tasks(prev_mutation);
382376
}
377+
};
383378

384-
// Store this new mutation
385-
current_mutation.borrow_mut().replace(mutation.clone());
379+
let mut current_mutation = use_hook(|| {
380+
make_mutation(&mutation, None);
381+
Signal::new(mutation.clone())
382+
});
386383

387-
mutation
388-
}));
384+
if *current_mutation.read() != mutation {
385+
let prev = mem::replace(&mut *current_mutation.write(), mutation.clone());
386+
make_mutation(&mutation, Some(prev));
387+
}
389388

390-
// Update the query tasks when the scope is dropped
389+
// Update the mutation tasks when the scope is dropped
391390
use_drop({
392391
move || {
393-
storage.update_tasks(mutation.peek().clone());
392+
storage.update_tasks(current_mutation.peek().clone());
394393
}
395394
});
396395

397-
UseMutation { mutation }
396+
UseMutation {
397+
mutation: current_mutation,
398+
}
398399
}

src/query.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -713,19 +713,14 @@ pub fn use_query<Q: QueryCapability>(query: Query<Q>) -> UseQuery<Q> {
713713
None => provide_root_context(QueriesStorage::<Q>::new_in_root()),
714714
};
715715

716-
let current_query = use_hook(|| Rc::new(RefCell::new(None)));
717-
718-
let mut make_query = |query: &Query<Q>| {
716+
let mut make_query = |query: &Query<Q>, mut prev_query: Option<Query<Q>>| {
719717
let query_data = storage.insert_or_get_query(query.clone());
720718

721719
// Update the query tasks if there has been a change in the query
722-
if let Some(prev_query) = current_query.borrow_mut().take() {
720+
if let Some(prev_query) = prev_query.take() {
723721
storage.update_tasks(prev_query);
724722
}
725723

726-
// Store this new query
727-
current_query.borrow_mut().replace(query.clone());
728-
729724
// Immediately run the query if enabled and the value is stale
730725
if query.enabled && query_data.state.borrow().is_stale(query) {
731726
let query = query.clone();
@@ -735,22 +730,24 @@ pub fn use_query<Q: QueryCapability>(query: Query<Q>) -> UseQuery<Q> {
735730
}
736731
};
737732

738-
let mut curr_query = use_hook(|| {
739-
make_query(&query);
733+
let mut current_query = use_hook(|| {
734+
make_query(&query, None);
740735
Signal::new(query.clone())
741736
});
742737

743-
if *curr_query.read() != query {
744-
curr_query.set(query);
745-
make_query(&*curr_query.read());
738+
if *current_query.read() != query {
739+
let prev = mem::replace(&mut *current_query.write(), query.clone());
740+
make_query(&query, Some(prev));
746741
}
747742

748743
// Update the query tasks when the scope is dropped
749744
use_drop({
750745
move || {
751-
storage.update_tasks(curr_query.peek().clone());
746+
storage.update_tasks(current_query.peek().clone());
752747
}
753748
});
754749

755-
UseQuery { query: curr_query }
750+
UseQuery {
751+
query: current_query,
752+
}
756753
}

0 commit comments

Comments
 (0)