errorhandling.rs 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. //! Example: Error Handling
  2. //! ------------------------
  3. //!
  4. //! Error handling in Dioxus comes in a few flavors. Because Dioxus is a Rust project, Options and Results are obviously
  5. //! the go-to way of wrapping possibly-errored data. However, if a component fails when "unwrapping," everything will crash,
  6. //! the page will deadlock, and your users will be sad.
  7. //!
  8. //! So, obviously, you need to handle your errors.
  9. //!
  10. //! Fortunately, it's easy to avoid panics, even during quick prototyping.
  11. //!
  12. //! Here are a few strategies:
  13. //! - Leverage the ability to return "None" and propagate None directly
  14. //! - Instead of propagating "None" manually, use the "?" syntax sugar
  15. //! - Convert Results into Options with .ok()
  16. //! - Manually display a separate screen by matching on Options/Results
  17. //!
  18. //! There *are* plans to add helpful screens for when apps completely panic in Wasm. However, you should really try to
  19. //! avoid panicking.
  20. use dioxus::prelude::*;
  21. fn main() {}
  22. /// This is one way to go about error handling (just toss things away with unwrap).
  23. /// However, if you get it wrong, the whole app will crash.
  24. /// This is pretty flimsy.
  25. static App: FC<()> = |(cx, props)| {
  26. let data = get_data().unwrap();
  27. cx.render(rsx!( div { "{data}" } ))
  28. };
  29. /// This is a pretty verbose way of error handling
  30. /// However, it's still pretty good since we don't panic, just fail to render anything
  31. static App1: FC<()> = |(cx, props)| {
  32. let data = match get_data() {
  33. Some(data) => data,
  34. None => return None,
  35. };
  36. cx.render(rsx!( div { "{data}" } ))
  37. };
  38. /// This is an even better form of error handling.
  39. /// However, it _does_ make the component go blank, which might not be desirable.
  40. ///
  41. /// This type of error handling is good when you have "selectors" that produce Some/None based on some state that's
  42. /// already controlled higher in the tree. i.e. displaying a "Username" in a component that should only be shown if
  43. /// a user is logged in.
  44. ///
  45. /// Dioxus will throw an error in the console if the None-path is ever taken.
  46. static App2: FC<()> = |(cx, props)| {
  47. let data = get_data()?;
  48. cx.render(rsx!( div { "{data}" } ))
  49. };
  50. /// This is top-tier error handling since it displays a failure state.
  51. ///
  52. /// However, the error is lacking in context.
  53. static App3: FC<()> = |(cx, props)| match get_data() {
  54. Some(data) => cx.render(rsx!( div { "{data}" } )),
  55. None => cx.render(rsx!( div { "Failed to load data :(" } )),
  56. };
  57. /// For errors that return results, it's possible to short-circuit the match-based error handling with `.ok()` which converts
  58. /// a Result<T, V> into an Option<T> and lets you abort rendering by early-returning `None`
  59. static App4: FC<()> = |(cx, props)| {
  60. let data = get_data_err().ok()?;
  61. cx.render(rsx!( div { "{data}" } ))
  62. };
  63. /// This is great error handling since it displays a failure state... with context!
  64. ///
  65. /// Hopefully you'll never need to display a screen like this. It's rather bad taste
  66. static App5: FC<()> = |(cx, props)| match get_data_err() {
  67. Ok(data) => cx.render(rsx!( div { "{data}" } )),
  68. Err(c) => cx.render(rsx!( div { "Failed to load data: {c}" } )),
  69. };
  70. // this fetching function produces "nothing"
  71. fn get_data() -> Option<String> {
  72. None
  73. }
  74. // this fetching function produces "nothing"
  75. fn get_data_err() -> Result<String, &'static str> {
  76. Result::Err("Failed!")
  77. }