I want to design a component that has this UI. However, what I've come up with seems very bloated and I feel that it could be broken down even further for better separation of concerns.
What I've done is simply made the entire card into a single component where you can pass in the following params
<ResourceCard
imageUrl="https://imageUrl.com"
iconUrl="https://iconimageUrl.com"
type="WEBINAR"
typeDescription="60 min video"
bodyTitle="Holiday Email: What to Know Before You Send"
body="Learn from our team of email..."
ctaText="Watch the webinar"
ctaUrl="https://exampleLink.com"
/>
Can this be separated further? Essentially I only have 1 component which handles rendering AND implementation of every section of this card. But I'm unsure what the best practice is when breaking something like this card down into further components.
Related
I'm using GraphQL + Relay in my app and find myself wrapping almost every component with createFragmentContainer, including those very low in the DOM hierarchy (usually functional components).
Is that the right way to use fragments? I'm wondering what are the guidelines for when to wrap components in fragment containers? Seems redundant to wrap a component when it only needs one field and I can pass that data from the parent via props.
I'm using Relay but I think the concepts are similar to Apollo as well.
This is the answer from my co-worker Jan Kassens who works on the Relay team:
If splitting out components makes sense to you, you should go for it. I find smaller modules generally help making code more understandable.
Now, a Button component probably doesn't have to have a fragment attached to it, but if it's a "Like Page" button with a mutation and maybe label specific to the page, I think it makes total sense to make that it's own fragment container.
As with so many things in engineering, there's probably trade offs in splitting out too much, but we've spent a lot of thought on making fragment containers as lightweight and efficient as we can so you shouldn't think too hard about introducing overhead.
Yes, it is. Instead of querying all the data on root component and pass to others as props, you should create fragment containers and each of this component query its own data. And due to relay data masking, these data from fragments can only be seen inside the component that required it.
Maybe this is a good reading: https://medium.com/entria/relay-apollo-anti-pattern-d9f4dea47738
And this on Data Masking: https://facebook.github.io/relay/docs/en/thinking-in-relay.html
Hope it helps :)
I'm new to React and trying to get how to build a good app architecture with it.
I also use typescript with all that features: interfaces, async-await, generics, etc. So, I'm puzzled about implementing some patterns:
1) Dependency Injection and reusable component instances
The first thing I can't get through is DI. Let's say we got a component class UserProfile that requires some dependencies like UserProvider. It would be perfect if the component instance (with deps injected) could be reusable, but I'm afraid it's only my dreams, not the react guys'. :)
So, I'm supposed to place this component this way:
<UserProfile id={123} />
Ok, what's the proper way to inject the dependency here? As an attribute like this <UserProfile id={123} dependency={userProvider: userProviderInstance} />?
Don't you think it is weird to put component input data, options/parameters and dependencies all together? I'd be happy if I could clearly separate them and put generic restrictions on the component class. What's the best practice?
Another side of impossibility to reuse component instances is the fact we must carry some needless objects through all the components structure just to inject them somewhere deep at the bottom. And nobody tells you what component does really use them. And try to imagine what adding a dependency to a low-level component will take in a large project. I just can't.
2) Using Promises
Let's consider a simple component that is supposed to render a counter: <Counter value={123} />.
Now, value is got from some API by calling a method getCounter(id: number): Promise<number>;, so the obvious way to put all together could look like this:
<Counter value={await provider.getCounter(id)} />
But i't impossible, I know. The common practice tells us to make it through setState method and rerender the component after the value is received.
Now imagine that the parent component is pretty complex and has many different providers. So, the parent component may not have definite state typing. It also may be conditional, you know...
You could suggest me implement the async getting in the Counter component, but i will refuse for a simple reason: That component does not know anything about the value's origin. In other cases the value is passed directly as a number. So, do you got better ideas how to keep code clean and simple while using promises?
Please, let me know if you come across some good articles or have your own experience in solving these issues.
PS: Thanks for attention! :)
This topic is a subject of bias - so below I will give my very personal thoughts on the topic that does not pretend to be absolute truth.
DI.
This is indeed not so common pattern in react as it is in angular. But having both context and properties in components allows you to archive the same level of separation as with pure DI. Check the context - it will help you to get rid of passing same props through the whole component tree. There are quite a few articles on this topic already (one, two) - check them out. Also you might be interested in reading this thread).
Promises
I do not really see any problem here. React has a simple concept - basically you have state and based on this state your app can render itself. Whereas rendering is not async operation - the preparation/update of the state can easily be done asynchronously and after results are assigned to the corresponding parts of the state - the necessary child components will be updated automatically. If you component has no knowledge of how to obtain value - it should not try to do it in first place - value should be passed down as props.
I'm fairly new to react, and really enjoying it. In creating components, is there a good rule of thumb (or simple generalization) to consider when deciding if a component should manage it's own state or not.
As example (only as example), an input that gets different classes added based on state, like 'hover', or 'not empty'...
Would it be better to create a component that manages those states internally or just handle that wherever I'm rendering an input?
I know this question may be 'primarily opinion based', but I'm hoping to get a general feel for how to think about it.
Thanks in advance,
-Ted
This is a constant internal battle that you'll just decide on down the line and you're right that it's primarily opinion based (meaning no answer will be correct). However, I can share my own experience and the process I take to decide on how to split the logic of my components.
I think of these things:
How will having/not having that piece of logic affect unit tests? If the component would need too much setup to be tested, then I move some logic into it and away from a parent Container component.
How often will I reuse the component? If it's many many times, then I look at the types of Container components that would render it and, again, if it seems like too much boilerplate is needed, then move the logic.
Does the value change through its own behavior or based on outside queues? In your example of the hover, the behavior changes due to its own behavior so it feels like the className (a prop of itself) is reacting to the component itself.
Most importantly, do you benefit from removing the logic and placing it in the Container? If you think that other component could benefit from knowing the hover state of your input field, then you may want to put the logic in the container. Otherwise you're abstracting away too much.
Application state management libraries such as Redux will often suggest to use their libraries as little as possible and instead rely on internal state of the component. I mention this because as you figure out where to put your logic, you have to think that about the end goal, which is usually to create a web application, with multiple components working together. Abstract too little and you end up creating non-reusable components. Abstract too much and you have tons of boilerplate and configuration lying around that could be trimmed by using internal state.
Zeke has some absolutely great points. I'd just like to add my own guideline, which is:
If the behavior of the component is the same, no matter where it's used, and is not tied to the behavior of the app/environment at large, then state should be internal
otherwise, manage state elsewhere and pass in props
Let's say I have a really dumb component A. I don't want any of the rendering logic from data to go in this component. Just take some raw data and display it.
Which is the more react way of going about this?
Creating just a bog standard factory function, that given different flags will create a new component with different props set
Making a wrapping component which does all the logic and sets the correct props from the data.
My fear with creating a wrapper is it is just more bloat in the chain of components. When this feels more a tangent.
Actually separating logic from presentation is pretty usual in React and considered best practise. So solution 2 is the way to go.
Your component A would then probably be a stateless function http://facebook.github.io/react/docs/reusable-components.html#stateless-functions whereas it's father would have only logic methods.
For your information, such a scheme is also the default way of using redux store, see http://redux.js.org/docs/basics/UsageWithReact.html#presentational-and-container-components
I'm debating refactoring parts of a site I'm working on from jQuery into react. Before I start I'd appreciate some feedback on my thought process so far.
<DeviceChooser>
<ManufacturerSelect />
<DeviceSelect />
<ButtonOne />
<ButtonTwo />
<DeviceChooser>
That is the desired component. It's behavior is:
The parent (DeviceChooser) gets some json data via ajax on componentWillMount.
It passes part of that data to ManufacturerSelect, which is a select field.
Once something is selected there, DeviceChooser passes some other data to DeviceSelect, which is also a select field.
Once something is selected there, if some conditions are met, both Button1 and Button2 become active
Clicking Button1 or Button2 would redirect the page to a specified url, with parameters set depending on the 2 select fields.
More practically speaking, you choose your phone manufacturer, then in the next select you choose your device from that manufacturer, then you get redirected to either page1 or page2 with some get parameters depending on the button you press.
My questions are:
Who's responsibility should it be to decide whether the buttons should be active? The DeviceChooser or the Buttons?
Who should compose the redirect URL? The Chooser or the Buttons?
I'm going to have variations of this DeviceChooser component all over the website, what can I do to ensure at least some reusability? The caveat being that sometimes it will have more select fields that just 2, and other times different select fields will be part of the equation depending on state (Like, if your device is a laptop, you also specify what shape of edges the device has)
I'm really grateful to any feedback at all. I've also created a Gist with the code I've come up with so far, if it helps.
One of the methodologies that I have followed since getting invested in React is using containers. Containers essentially are components that are responsible for retrieving and manipulating the data and then passing all the relevant data down to all the child "dumb" components that are simply responsible for rendering said data.
Operating under this premise (or something similar) I would suggest doing calculations in the container on the initial data, and pass everything down.
So in this instance we should be do the following in the container (or parent component)
Get JSON data via componentWillMount
Manipulate the data and pass it to ManufacturerSelect
The other questions depend on which framework you're using. Are you able to elaborate on this? Are you using Redux, Flux, ReFlux etc?
I've had a quick look at your code, one super useful thing that I think you should do is specify PropTypes for each component. This helps immensely for debugging, and when you're talking about reusing components in several distinct locations this will be crucial. Also (without understanding the full context) is it necessary to use state everywhere in your components? Would it be possible for them to simply render the props passed down to them? (again this depends a little on the store you'
re using).
It's a relatively generic question, but my line of thinking (quite opinionated) would be as follows:
Your Buttons should become simple, generic Button components that should for this example have the following props (besides perhaps some styling props):
disabled
title
onClick
Your Device Chooser is the one who's got the awareness that components mix together, that these buttons should actually continue to do something after they're clicked, so you'll want to handle that knowledge solely within that component. It glues the rest together (passes data around) and should therefore also make these decisions.
<DeviceChooser>
<ManufacturerSelect data={this.state.manufacturers} />
<DeviceSelect data={this.state.devices} />
<Button
disabled={this.state.selectedManufacturer === null ? true : false}
title='Manufactuer details'
onClick={this.handleManufacturerDetailsClick.bind(this, this.state.selectedManufactuer}}
/>
<Button
disabled={this.state.selectedDevice === null ? true : false}
title='See device details'
onClick={this.handleDeviceDetailClick.bind(this, this.state.selectedDevice }}
/>
<DeviceChooser>
Device chooser's method than can be something like:
handleDeviceDetailClick(device) {
history.pushState('/device/detail/' + device.id);
}
You want to separate your functional components from the stateless ones. A good read for this is http://tylermcginnis.com/functional-components-vs-stateless-functional-components-vs-stateless-components/