Dioxus에서 비동기 API 요청을 처리하는 방식에는 use_future, use_coroutine, use_resource, use_signal + spawn_local 등이 있습니다.
각 방식은 사용 목적과 장단점이 다르므로, 어떤 상황에서 어떤 방식을 써야 하는지 정리해 보겠습니다.
use_future – 1회성 비동기 요청useEffect(() => fetchData(), [deps])와 비슷한 개념. #[component]
fn FetchDataWithFuture() -> Element {
let data_future = use_future(|| async {
get_server_data().await.unwrap_or_else(|_| "Failed to fetch data".to_string())
});
rsx! {
div {
match data_future() {
Some(data) => rsx! { "Server Response: {data}" },
None => rsx! { "Loading..." }
}
}
}
}
✔ 한 번만 실행됨 → 불필요한 API 요청 방지
✔ 단순한 데이터 가져오기에 적합
✖ 수동 갱신이 어렵다 → 새로운 요청을 보내려면 use_future를 다시 생성해야 함
✖ 초기 렌더링에서 항상 실행됨
use_resource – 데이터 로딩 및 자동 갱신useQuery(React Query)와 비슷한 개념 #[component]
fn FetchDataWithResource() -> Element {
let data_resource = use_resource(|| async {
get_server_data().await.unwrap_or_else(|_| "Failed to fetch data".to_string())
});
rsx! {
div {
match data_resource() {
Some(data) => rsx! { "Server Response: {data}" },
None => rsx! { "Loading..." }
}
}
}
}
✔ 자동으로 데이터를 가져오고 관리 → 불필요한 수동 업데이트 필요 없음
✔ UI와 연동하여 변경 감지 가능
✖ 새로운 요청을 보내려면 상태를 리셋해야 함
✖ 데이터 변경 시 갱신 로직이 필요할 수 있음
use_signal + spawn_local – 명시적 API 호출use_signal로 상태를 관리하고, spawn_local을 사용하여 비동기 데이터를 명시적으로 가져옴 useState + useEffect 패턴과 비슷 #[component]
fn FetchDataWithSignal() -> Element {
let mut response = use_signal(String::new);
let mut is_loading = use_signal(|| false);
rsx! {
div {
button {
class: "border p-2 rounded-sm",
onclick: move |_| {
is_loading.set(true);
spawn_local(async move {
match get_server_data().await {
Ok(data) => response.set(data),
Err(_) => response.set("Failed to fetch data".to_string()),
}
is_loading.set(false);
});
},
"Fetch Data"
}
p {
if is_loading() { "Loading..." } else { "{response}" }
}
}
}
}
✔ 사용자가 원할 때 API 요청 가능 → 불필요한 요청 방지
✔ 로딩 상태 및 오류 처리 간편
✔ 버튼 클릭 등 특정 이벤트에서 요청하기 좋음
✖ 자동 갱신 기능 없음 → 데이터 갱신을 원하면 직접 관리해야 함
use_coroutine – 이벤트 기반 비동기 처리useEffect + WebSocket과 유사 #[component]
fn FetchDataWithCoroutine() -> Element {
let mut response = use_signal(String::new);
let coroutine = use_coroutine(|rx| async move {
while let Some(_) = rx.next().await {
if let Ok(data) = get_server_data().await {
response.set(data);
}
}
});
rsx! {
div {
button {
class: "border p-2 rounded-sm",
onclick: move |_| coroutine.send(()),
"Fetch Data"
}
p { "{response}" }
}
}
}
✔ 비동기 이벤트 기반 동작 가능 → 특정 이벤트 발생 시 데이터 요청
✔ 실시간 데이터 감시(WebSocket 등) 가능
✔ 여러 개의 요청을 효율적으로 처리할 수 있음
✖ 일반적인 API 요청에는 오버킬
✖ 비동기 흐름 관리가 다소 복잡
| 방식 | 사용 목적 | 장점 | 단점 | 추천 상황 |
|---|---|---|---|---|
use_future | 1회성 API 요청 | 단순, 불필요한 재실행 방지 | 수동 갱신 어려움 | 초기 렌더링 시 API 요청 |
use_resource | 자동 데이터 로딩 | UI 자동 갱신, 유지보수 쉬움 | 새로운 요청 트리거 어려움 | 자동으로 데이터 가져오고 관리 |
use_signal + spawn_local | 명시적 API 호출 | 로딩/에러 관리 쉬움, 요청 제어 가능 | 자동 갱신 없음 | 버튼 클릭 시 API 요청 |
use_coroutine | 이벤트 기반 비동기 처리 | 실시간 감시 가능, 다중 요청 관리 | 일반적인 API 요청에는 불필요하게 복잡 | WebSocket, 실시간 API 요청 |
use_futureuse_resourceuse_signal + spawn_localuse_coroutine⚡ 대부분의 경우 use_signal + spawn_local이 가장 유연하고 추천됨!
그러나 상황에 따라 적절한 방식을 선택하는 것이 중요합니다. 🎯