Skip to content

Optimization in use_reducer#3945

Merged
Madoshakalaka merged 5 commits intoyewstack:masterfrom
Pascal-So:use_reducer_optimization
Feb 28, 2026
Merged

Optimization in use_reducer#3945
Madoshakalaka merged 5 commits intoyewstack:masterfrom
Pascal-So:use_reducer_optimization

Conversation

@Pascal-So
Copy link
Copy Markdown
Contributor

Description

Yew currently provides two versions of the reducer hook:

  • use_reducer: This hook always causes a re-render when an action is dispatched.
  • use_reducer_eq: This hook avoids the re-render if the new state is the same as the old state. However, the state now has to implement PartialEq.

I feel like there is room for a middle ground: The reducer takes an Rc and returns an Rc. Even if we don't have a PartialEq implementation on the state, we can still know that the state must be unchanged if the reducer returns the exact same Rc back to us. This check is almost free (just a pointer comparison).

This PR adds a simple check if the two Rcs are the same, and in that case skip the re-render.

Note that even for use_reducer_eq this check is beneficial, since the PartialEq implementation might be more expensive than just a pointer comparison.

This change might be a breaking change if someone was relying on the exact number of re-renders, but I'd assume that this is not covered in Yew's semver guarantees, right?

Checklist

  • I have reviewed my own code
  • I have added tests

@github-actions
Copy link
Copy Markdown

github-actions bot commented Nov 16, 2025

Visit the preview URL for this PR (updated for commit b8538ba):

https://yew-rs-api--pr3945-use-reducer-optimiza-z0yvauva.web.app

(expires Sat, 07 Mar 2026 03:09:16 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

@github-actions
Copy link
Copy Markdown

github-actions bot commented Nov 16, 2025

Benchmark - core

Yew Master

vnode           fastest       │ slowest       │ median        │ mean          │ samples │ iters
╰─ vnode_clone  3.945 ns      │ 4.08 ns       │ 3.947 ns      │ 3.951 ns      │ 100     │ 1000000000

Pull Request

vnode           fastest       │ slowest       │ median        │ mean          │ samples │ iters
╰─ vnode_clone  4.018 ns      │ 4.381 ns      │ 4.02 ns       │ 4.025 ns      │ 100     │ 1000000000

@github-actions
Copy link
Copy Markdown

github-actions bot commented Nov 16, 2025

Benchmark - SSR

Yew Master

Details
Benchmark Round Min (ms) Max (ms) Mean (ms) Standard Deviation
Baseline 10 274.848 275.548 275.073 0.219
Hello World 10 445.426 457.397 449.457 3.592
Function Router 10 38742.516 39232.926 39002.762 170.422
Concurrent Task 10 1004.942 1006.867 1006.153 0.652
Many Providers 10 1017.577 1046.280 1031.017 7.837

Pull Request

Details
Benchmark Round Min (ms) Max (ms) Mean (ms) Standard Deviation
Baseline 10 281.701 282.900 281.942 0.373
Hello World 10 449.760 469.706 456.194 6.691
Function Router 10 32356.442 32962.141 32763.153 169.503
Concurrent Task 10 1005.229 1006.677 1006.016 0.513
Many Providers 10 1052.713 1095.280 1071.041 12.691

@github-actions
Copy link
Copy Markdown

github-actions bot commented Nov 16, 2025

Size Comparison

Details
examples master (KB) pull request (KB) diff (KB) diff (%)
async_clock 100.197 100.197 0 0.000%
boids 168.080 168.080 0 0.000%
communication_child_to_parent 93.469 93.469 0 0.000%
communication_grandchild_with_grandparent 105.250 105.250 0 0.000%
communication_grandparent_to_grandchild 101.606 101.606 0 0.000%
communication_parent_to_child 90.900 90.900 0 0.000%
contexts 105.149 105.152 +0.003 +0.003%
counter 86.282 86.282 0 0.000%
counter_functional 88.272 88.275 +0.003 +0.003%
dyn_create_destroy_apps 90.321 90.321 0 0.000%
file_upload 99.346 99.346 0 0.000%
function_delayed_input 94.375 94.378 +0.003 +0.003%
function_memory_game 172.939 172.945 +0.006 +0.003%
function_router 405.547 405.590 +0.043 +0.011%
function_todomvc 164.148 164.162 +0.014 +0.008%
futures 235.159 235.159 0 0.000%
game_of_life 104.718 104.718 0 0.000%
immutable 255.868 255.871 +0.003 +0.001%
inner_html 80.803 80.803 0 0.000%
js_callback 109.374 109.377 +0.003 +0.003%
keyed_list 179.724 179.724 0 0.000%
mount_point 84.146 84.146 0 0.000%
nested_list 113.058 113.058 0 0.000%
node_refs 91.525 91.525 0 0.000%
password_strength 1728.826 1728.826 0 0.000%
portals 93.035 93.035 0 0.000%
router 376.134 376.140 +0.006 +0.002%
suspense 113.452 113.455 +0.003 +0.003%
timer 88.634 88.634 0 0.000%
timer_functional 98.875 98.880 +0.005 +0.005%
todomvc 142.088 142.088 0 0.000%
two_apps 86.146 86.146 0 0.000%
web_worker_fib 136.224 136.237 +0.014 +0.010%
web_worker_prime 187.438 187.466 +0.027 +0.015%
webgl 83.223 83.223 0 0.000%

✅ None of the examples has changed their size significantly.

@Madoshakalaka Madoshakalaka added breaking change A-yew Area: The main yew crate labels Feb 28, 2026
@Madoshakalaka Madoshakalaka force-pushed the use_reducer_optimization branch from 5e3dadf to b8538ba Compare February 28, 2026 03:07
@Madoshakalaka
Copy link
Copy Markdown
Member

rebased onto master

since it's a breaking change, will probally release with yew 0.23

@Madoshakalaka
Copy link
Copy Markdown
Member

I looked at the SSR benchmarks and Function Router is the only one that has use_reducer usage (5 distinct use_reducer/use_reducer_eq call sites across its components)

It does show a massive performance gain above (~39,000ms → ~32,700ms (20% faster) )

I think it's a solid improvement

@Madoshakalaka Madoshakalaka merged commit b5c91a5 into yewstack:master Feb 28, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants