(no title)
onsclom | 2 years ago
This behavior exists without inheritance as well! Let's imagine we want to use our existing `HelloText` component. But like you suggested, let's subscribe to the `onclick` signal and add a `bolded` property. When the user clicks the text, it will toggle the bolded property. We will use React because it's famous for not using inheritance.
```jsx function HelloText(props) { return <Text {...props}>Hello World!</Text>; }
export default function App() { const [bolded, setBolded] = React.useState(false); return <HelloText onClick={() => setBolded(bold => !bold) bold={bolded}} /> } ```
And just like you wanted, even children of `<Text>` could reference `bold` and `onClick`. I'll assume you know what that would look like. If not, let me know and I'm happy to make examples for that too. You can provide default prop values that can be overridden. You can accept functions. You can expose signals.
If you are being attentive, you might have noticed the code that enables this behavior: `{...props}` is the explicit way to pass all the props from the parent `HelloText` to its child `Text`. Unlike React, exposing props is implicit and automatic in QML. Though its trivial to make every component expose all their props to their children, the docs argue that you should avoid this. They say that if you find yourself doing this a lot, you are probably designing things poorly [1].
Here's how I understand this: If you are going back and wishing you exposed more properties or methods all the time, then you are probably developing things top down instead of bottom up. When building UI, it's easier and better if you start by building the smallest possible pieces of your UI. Then you can compose them into bigger, more complex pieces. The other way around is dangerous because you would be designing inherently inflexible abstractions. Even the most elaborate and beautiful castle made of yarn will never be as flexible as a castle made of legos.
For example, when and why would you want this `CustomRowLayout` component? Instead, simply start with the smallest easiest parts of your app. Build the buttons inside that row. Maybe the row has a dropdown item, so you can build that. Compose those parts using `RowLayout`, `ColumnLayout`, `GridLayout`, and `Flow`. Maybe make yourself yourself a `Spacer`. While you build your apps' custom rows in this pattern, you will 1. naturally develop a great toolbox of composable components that are flexible and useful and 2. have a much easier time than reimplementing some method on a `CustonRowLayout` component! Previously you asked me for an example where inheritance is a footgun in UI development. A `CustomRowLayout` is an example as building new row layouts bottom up is clearly superior.
But also, React and other modern UI frameworks won't stop you from building `CustomRowLayout` if that's what you really want. Hopefully now it's clear that you can build something like this using React, Svelte, or any other modern UI framework without inheritance. And also, if you find yourself doing this often, maybe that's a sign you are approaching problems from the wrong direction.
> In QML composition is when one places children elements within a component and expose relevant properties and signals to the parent. So I disagree on this part
Honestly, I think this is a fair distinction and definition. Though, then things get a bit hairy on the other side. Clearly React and Svelte support the alternative behavior that you call inheritance in QML. What do you call that now? Did React and Svelte suddenly become OOP frameworks too?
I think the important conclusion is that building complex UI using composition in a bottom up fashion is 1. possible and 2. optimal. QML, Svelte, and React all allow developing top down and bottom up, which is great. Svelte and React simply make top down development explicit.
I will leave things with a message from React's composition vs inheritance page: "At Facebook, we use React in thousands of components, and we haven’t found any use cases where we would recommend creating component inheritance hierarchies.
Props and composition give you all the flexibility you need to customize a component’s look and behavior in an explicit and safe way. Remember that components may accept arbitrary props, including primitive values, React elements, or functions." [2]
[1] https://react.dev/learn/passing-props-to-a-component#forward... [2] https://legacy.reactjs.org/docs/composition-vs-inheritance.h...
No comments yet.