Replies: 1 comment
-
Hello! To achieve this while keeping type safety in mind, you can use enums and pattern matching like so: use dioxus::prelude::*;
fn main() {
dioxus::launch(App);
}
#[derive(Clone, PartialEq)]
enum Tab {
Main,
Artist,
Album,
Help,
Custom(Callback<i32, Element>),
}
impl Tab {
fn render(&self, tab_index: i32) -> Element {
match self {
Tab::Main => rsx! { MainPage { tab_index } },
Tab::Artist => rsx! { ArtistPage { tab_index } },
Tab::Album => rsx! { AlbumPage { tab_index } },
Tab::Help => rsx! { HelpPage {} },
Tab::Custom(element) => element.call(tab_index),
}
}
}
#[component]
fn App() -> Element {
rsx! {
TabbedLayout {
tabs: vec![
Tab::Main,
Tab::Artist,
Tab::Album,
Tab::Help,
Tab::Custom(Callback::new(move |tab_index| rsx! { MainPage { tab_index } }))
],
}
}
}
#[component]
fn TabbedLayout(tabs: Vec<Tab>) -> Element {
let tab_index = 1;
rsx! {
for tab in tabs.iter() {
{tab.render(tab_index)}
}
}
} By defining each tab as a variant of the Hope this helps! |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm looking for a way to create components that have "holes" in their rendering that can be filled by callers. In React, you could do this with "render props", which are either normal props or the special
children
prop which have a type like(SomeData) => React.ReactElement
. This is very useful because it allows you to create generic components like layouts which not only let callers provide content to be rendered (which may or not be actually rendered depending on the situation), but also let the component pass data of its own to the content.As an example, let's say I want to make a generic "tabbed layout" component. It will display one tab at a time and should only render the contents of that single tab. Let's say the tab may also be interested in knowing what index in the list of tabs it is being rendered at (this isn't a very realistic part of the example, but is illustrating a requirement of passing data to the rendered content which is generally useful). In React, I could implement this roughly like:
So callers can pass in an array of "lazy" tab content renderers, which can also make use of their current tab index. I could use it like so:
I haven't found any way to do something even roughly equivalent in Dioxus. I've seen various suggestions that almost but don't quite seem to work as I'd like:
Callback<SomeData, Element>
doesn't seem appropriate since I want to call the function in the render body of my component (which violates an expectation documented onCallback::new
), and creating a callback seems to require using a hook, but it's much better for ergonomics if I can construct these render functions inline when rendering the component, which may be rendered conditionally.fn(SomeData) -> Element
almost works, but can't capture any data which is a big restriction.Ideally, I'd like a Dioxus solution to look as close as possible to this:
I know there are other potential complications with creating a
Vec
of closures due to them having different types, but let's ignore that for this discussion; many of my actual use-cases involve taking only a single "render prop" where that isn't an issue. A more realistic example would be a component which gets passed a "possibly-not-yet-loaded-from-the-server" value and renders a generic loading state if the value isn't ready yet, but if it is ready, passes the ready value to a "render prop" that displays the value.Another obvious example is something as simple as a generic "select a choice from a list of possible choices" component, which needs to know how to render the selected choice and each choice in the list. How can this component be made generic so that the caller decides how the items are rendered? I suppose you could literally make it generic in the Rust sense, and require the choice type to implement a trait that decides how it's rendered, but I'm not sure that works for every case and would be very verbose if you have to implement a trait every time you want to use it, and the rendering logic can't capture data from the usage site.
Beta Was this translation helpful? Give feedback.
All reactions