Giter Site home page Giter Site logo

Comments (8)

markuswustenberg avatar markuswustenberg commented on June 16, 2024

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.

tbo avatar tbo commented on June 16, 2024

@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.

markuswustenberg avatar markuswustenberg commented on June 16, 2024

@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.

tbo avatar tbo commented on June 16, 2024

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.

markuswustenberg avatar markuswustenberg commented on June 16, 2024

@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.

tbo avatar tbo commented on June 16, 2024

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.

markuswustenberg avatar markuswustenberg commented on June 16, 2024

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.

kynrai avatar kynrai commented on June 16, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.