Comments (9)
I'm closing this now, since I'm not sure it's a solution in gomponents itself that's required.
from gomponents.
Hi @tbo, thank you for your issue!
Unfortunately, I don't consider changing the Node
interface in a breaking manner an option at this point.
I would recommend you pass a top-level domain-specific context struct down to components (like props in React) with the information the components need. I think this fits well with how it's handled in Go generally, with the context
package used extensively in the stdlib. This also makes it less "magic", which I also think aligns well with idiomatic Go.
I guess this is what you mean with "prop drilling" (?), but I think that's currently the best option I can think of. :)
from gomponents.
@markuswustenberg I agree that passing a context property is often the cleanest and most idiomatic solution in Golang. By "prop drilling," I meant the anti-pattern often encountered in React projects, where excessive reliance on property passing can complicate code maintenance, especially in complex projects. I also agree that avoiding a breaking change is important, and I was hoping for a suggestion of a non-breaking alternative.
from gomponents.
@tbo I've been thinking about this a bit. Isn't any solution pretty much orthogonal to what gomponents offers? Since what this library basically does is caring about how components are rendered, but not so much about how they are constructed.
I can see how e.g. some helper functions or documentation could help with this, but I'm not so sure how exactly that would look, since people's needs and usages differ so much. Thoughts?
from gomponents.
Isn't any solution pretty much orthogonal to what gomponents offers? Since what this library basically does is caring about how components are rendered, but not so much about how they are constructed.
I would distinguish between two categories of concerns: Firstly, a Gomponents counterpart to React's context - I agree that passing a context argument is the best approach here. Secondly, there are cases that only affect the rendering aspect, not the business logic. Internationalization and theming are good examples. Other templating engines offer fitting solutions here. For instance, html/template
allows the definition of translation functions via FuncMap: https://pkg.go.dev/github.com/nicksnyder/go-i18n/i18n#example-package-Template
I was hoping to achieve something similar. If Gomponents could propagate a "render context," then users could extend it in this way:
type MyContext struct {
language string
}
func T(message string) Node {
return NodeFunc(func(w io.Writer, c interface{}) error {
_, err := w.Write([]byte(translate(message, c.(MyContext).language)))
return err
})
}
func CheckoutButton() Node {
return Div(T("checkout.action.order"))
}
func main() {
node := CheckoutButton()
node.Render(os.Stdout, MyContext{language: "en"})
}
from gomponents.
@tbo html/template
needs that because there's no other way to pass functions to templates on a global level, right? gomponents, on the other hand, is just Go code. So if you need a global translation function, just create a function that you can call in any component (say i18n.T
) and use that?
I guess there's a part of the problem I'm not really understanding here?
from gomponents.
The issue lies not in passing a function, but in passing the language property. html/template
can define a global function for each render, pre-configured with the desired language. The challenge I'm addressing is the need to pass locale information to every component. While this isn't problematic for smaller applications, it becomes a significant issue in complex ones. Consider a large UI component library where you want to add translations to a component widely used by others. You would then have to "drill" this property through all dependents. An alternative is to always pass a context property to every component, but this approach doesn't necessarily enhance readability.
Your experience may differ from mine, but as far as I know, the general consensus in component libraries is to use a context for these use cases. For example, see templ.
from gomponents.
Ah, thank you, now I think I understand the use case.
As I understand, prop drilling is a variant of what's used throughout the Go stdlib with context.Context
, right? The way e.g. HTTP handlers accept it to pass through the stack to enforce deadlines etc. Would using context.Context
as a parameter in all components alleviate the issue somewhat?
I'm not sure I would be able to figure out a different solution without changing the Node
interface (which I don't consider an option, at least not without doing a v2) or making some kind of hack, like checking whether the passed writer in the Render
function also has a GetContext() context.Context
method or something like that, similar to how some things have been backported in net/http
. Do you have any ideas?
from gomponents.
Even if you have a specific use case in mind with passing c interface{} I still think context is better and more understood.
At best I feel having another function on the render Interface like RenderCtx(ctx context.Context, w io.Writer) might work but then you need a way for the components to get the context
from gomponents.
Related Issues (20)
- Proposal: Re-export packages with shorter names (g, h, c) HOT 3
- Inline if with nil pointer HOT 8
- Why can't a group be rendered? HOT 11
- Add lib to awesome Go HOT 1
- Remove fmt.Stringer support? HOT 3
- trigger an error on duplicate attributes HOT 3
- Make Group renderable
- Proposal to Add String Rendering Method to Node Interface HOT 5
- HTML -> gomponents converter tool HOT 9
- Label can be an attribute as well HOT 2
- Missing list attribute HOT 1
- Figure out what can be done about name collisions between elements and attributes HOT 4
- Add new `[type]` links to godocs
- Drop support for pre Go 1.18? HOT 3
- Perhaps we can take inspiration from HOT 6
- JS Ternary like HOT 1
- Add `cite` attribute
- Is it possible to modify an existing gomponent?
- pretty output? HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gomponents.