|
| 1 | +use crate::{use_navigate, use_resolved_path, NavigateOptions}; |
| 2 | +use leptos::{component, provide_context, use_context, IntoView, Scope}; |
| 3 | +use std::rc::Rc; |
| 4 | + |
| 5 | +/// Redirects the user to a new URL, whether on the client side or on the server |
| 6 | +/// side. If rendered on the server, this sets a `302` status code and sets a `Location` |
| 7 | +/// header. If rendered in the browser, it uses client-side navigation to redirect. |
| 8 | +/// In either case, it resolves the route relative to the current route. (To use |
| 9 | +/// an absolute path, prefix it with `/`). |
| 10 | +/// |
| 11 | +/// **Note**: Support for server-side redirects is provided by the server framework |
| 12 | +/// integrations (`leptos_actix` and `leptos_axum`). If you’re not using one of those |
| 13 | +/// integrations, you should manually provide a way of redirecting on the server |
| 14 | +/// using [provide_server_redirect]. |
| 15 | +#[component] |
| 16 | +pub fn Redirect<P>( |
| 17 | + cx: Scope, |
| 18 | + /// The relative path to which the user should be redirected. |
| 19 | + path: P, |
| 20 | + /// Navigation options to be used on the client side. |
| 21 | + #[prop(optional)] |
| 22 | + options: Option<NavigateOptions>, |
| 23 | +) -> impl IntoView |
| 24 | +where |
| 25 | + P: std::fmt::Display + 'static, |
| 26 | +{ |
| 27 | + // resolve relative path |
| 28 | + let path = use_resolved_path(cx, move || path.to_string()); |
| 29 | + let path = path.get().unwrap_or_else(|| "/".to_string()); |
| 30 | + |
| 31 | + // redirect on the server |
| 32 | + if let Some(redirect_fn) = use_context::<ServerRedirectFunction>(cx) { |
| 33 | + (redirect_fn.f)(&path); |
| 34 | + } |
| 35 | + |
| 36 | + // redirect on the client |
| 37 | + let navigate = use_navigate(cx); |
| 38 | + navigate(&path, options.unwrap_or_default()) |
| 39 | +} |
| 40 | + |
| 41 | +/// Wrapping type for a function provided as context to allow for |
| 42 | +/// server-side redirects. See [provide_server_redirect] |
| 43 | +/// and [Redirect]. |
| 44 | +#[derive(Clone)] |
| 45 | +pub struct ServerRedirectFunction { |
| 46 | + f: Rc<dyn Fn(&str)>, |
| 47 | +} |
| 48 | + |
| 49 | +impl std::fmt::Debug for ServerRedirectFunction { |
| 50 | + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 51 | + f.debug_struct("ServerRedirectFunction").finish() |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +/// Provides a function that can be used to redirect the user to another |
| 56 | +/// absolute path, on the server. This should set a `302` status code and an |
| 57 | +/// appropriate `Location` header. |
| 58 | +pub fn provide_server_redirect(cx: Scope, handler: impl Fn(&str) + 'static) { |
| 59 | + provide_context( |
| 60 | + cx, |
| 61 | + ServerRedirectFunction { |
| 62 | + f: Rc::new(handler), |
| 63 | + }, |
| 64 | + ) |
| 65 | +} |
0 commit comments