component.rs 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. //! This file handles the supporting infrastructure for the `Component` trait and `Properties` which makes it possible
  2. //! for components to be used within Nodes.
  3. //!
  4. //! Note - using the builder pattern does not required the Properties trait to be implemented - the only thing that matters is
  5. //! if the type suppports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder
  6. //! that ensures compile-time required and optional fields on cx.
  7. use crate::innerlude::{Context, LazyNodes, VNode, FC};
  8. pub trait Properties: Sized {
  9. type Builder;
  10. const IS_STATIC: bool = false;
  11. fn builder() -> Self::Builder;
  12. /// Memoization can only happen if the props are 'static
  13. /// The user must know if their props are static, but if they make a mistake, UB happens
  14. /// Therefore it's unsafe to memeoize.
  15. unsafe fn memoize(&self, other: &Self) -> bool;
  16. }
  17. impl Properties for () {
  18. type Builder = EmptyBuilder;
  19. const IS_STATIC: bool = true;
  20. fn builder() -> Self::Builder {
  21. EmptyBuilder {}
  22. }
  23. unsafe fn memoize(&self, _other: &Self) -> bool {
  24. true
  25. }
  26. }
  27. // We allow components to use the () generic parameter if they have no props. This impl enables the "build" method
  28. // that the macros use to anonymously complete prop construction.
  29. pub struct EmptyBuilder;
  30. impl EmptyBuilder {
  31. #[inline]
  32. pub fn build(self) -> () {
  33. ()
  34. }
  35. }
  36. /// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern
  37. /// to initialize a component's props.
  38. pub fn fc_to_builder<T: Properties>(_: FC<T>) -> T::Builder {
  39. T::builder()
  40. }
  41. /// Create inline fragments
  42. ///
  43. /// Fragments capture a series of children without rendering extra nodes.
  44. ///
  45. /// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase.
  46. /// Try to avoid nesting fragments if you can. Infinitely nested Fragments *will* cause diffing to crash.
  47. #[allow(non_upper_case_globals, non_snake_case)]
  48. pub fn Fragment<'a>(cx: Context<'a, ()>) -> VNode<'a> {
  49. cx.render(LazyNodes::new(move |f| f.fragment_from_iter(cx.children())))
  50. }