memo.rs 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. //! Example: Memoization
  2. //! --------------------
  3. //!
  4. //! This example showcases how memoization works in Dioxus.
  5. //!
  6. //! Memoization is the process in which Dioxus skips diffing child components if their props don't change.
  7. //! In React, components are never memoized unless wrapped in `memo` or configured with `shouldComponentUpdate`.
  8. //!
  9. //! Due to the safety guarantees of Rust, we can automatically memoize components in some circumstances. Whenever a
  10. //! component's properties are valid for the `'static` lifetime, Dioxus will automatically compare the props before
  11. //! diffing the component. If the props don't change (according to PartialEq), the component will not be re-rendered.
  12. //!
  13. //! However, if the props use some generics or borrow from their parent, then Dioxus can't safely supress updates,
  14. //! and is forced to render the child. If you think that this behavior is wrong for your usecase, you can implement
  15. //! the memo method yourself, but beware, doing so is UNSAFE and may cause issues if you do it wrong.
  16. //!
  17. //! If you want to gain that little bit extra performance, consider using global state management, signals, or
  18. //! memoized collections like im-rc which are designed for this use case.
  19. use dioxus::prelude::*;
  20. fn main() {}
  21. // By default, components with no props are always memoized.
  22. // A props of () is considered empty.
  23. static Example: FC<()> = |cx| {
  24. cx.render(rsx! {
  25. div { "100% memoized!" }
  26. })
  27. };
  28. // These props do not borrow any content, and therefore can be safely memoized.
  29. // However, the parent *must* create a new string on every render.
  30. // Notice how these props implement PartialEq - this is required for 'static props
  31. #[derive(PartialEq, Props)]
  32. struct MyProps1 {
  33. name: String,
  34. }
  35. static Example1: FC<MyProps1> = |cx| {
  36. cx.render(rsx! {
  37. div { "100% memoized! {cx.name}" }
  38. })
  39. };
  40. // These props do not borrow any content, and therefore can be safely memoized.
  41. // In contrast with the `String` example, these props use `Rc<str>` which operates similar to strings in JavaScript.
  42. // These strings cannot be modified, but may be cheaply shared in many places without issue.
  43. #[derive(PartialEq, Props)]
  44. struct MyProps2 {
  45. name: std::rc::Rc<str>,
  46. }
  47. static Example2: FC<MyProps2> = |cx| {
  48. cx.render(rsx! {
  49. div { "100% memoized! {cx.name}" }
  50. })
  51. };
  52. // These props *do* borrow any content, and therefore cannot be safely memoized!.
  53. #[derive(PartialEq, Props)]
  54. struct MyProps3<'a> {
  55. name: &'a str,
  56. }
  57. // We need to manually specify a lifetime that ensures props and scope (the component's state) share the same lifetime.
  58. // Using the `static Example: FC<()>` pattern _will_ specify a lifetime, but that lifetime will be static which might
  59. // not exactly be what you want
  60. fn Example3<'a>(cx: Context<'a, MyProps3<'a>>) -> VNode {
  61. cx.render(rsx! {
  62. div { "Not memoized! {cx.name}" }
  63. })
  64. }
  65. // These props *do* borrow any content, and therefore cannot be safely memoized!.
  66. // However, they cannot be compared, so we don't need the PartialEq flag.
  67. #[derive(Props)]
  68. struct MyProps4<'a> {
  69. onhandle: &'a dyn Fn(),
  70. }
  71. // We need to manually specify a lifetime that ensures props and scope (the component's state) share the same lifetime.
  72. fn Example4<'a>(cx: Context<'a, MyProps4<'a>>) -> VNode {
  73. cx.render(rsx! {
  74. div { "Not memoized!", onclick: move |_| (cx.onhandle)() }
  75. })
  76. }