React component breakdown strategy - javascript

I need to implement components tree on React.
And I'm wondering what is good enough pattern how to break everything in tree
but with scaling(code or team) in mind.
Usually I'm using next way:
function UserAvatar(props) {
return <div><img src="" alt="" /></div>
}
function UserEmail(props) {
return <div>e-mail: some#email.com</div>
}
function UserSection(props) {
return (
<div className="container">
<div className="section">
<UserAvatar />
</div>
<div className="section">
<UserEmail />
</div>
</div>
);
}
But should I avoid all this layout divs and make layout cleaner?
One obvious option is to move into the separate component layout stuff.
Thanks

Guidelines on breaking down components:
When your component is doing too much. Components should ideally be focused on doing one (or a few, but not many) things. The most obvious sign is when the number of lines in the code is getting too long. As a rough estimate, components should not be more than 300 lines.
When you want to reuse components across multiple parent components, you'll have to break them up.
If you want to optimize the render() of specific subtrees of a componant via shouldComponentUpdate(), then you have to break them up as you can only implement shouldComponentUpdate() on the component-level.
Separating data fetching logic from rendering and handling user interactions logic. Instead of making one component do both data fetching and (rendering and handling user interactions), break them down into smaller components so that you can test the components separately:
Test that the first component fetches data.
Test that the second component renders the data properly and can respond to user interactions.
Read more about it here
Many more good answers by Kent C. Dodds here.

It's a good practice to keep each Component in their own files then import them where you need to reference them.
Also, in your example it's most likely you'll need to set the avatar url and email as props. Then make the UserAvatar and UserEmail render the values. Also, it's good practice to setup the propTypes, so other developers (and yourself) know which props to pass.
One criteria to break down components into subcomponents it's when they deal with different concerns, or when the file size is getting too large. Another criteria is when you need to re-use that component in some other context.
Hope this helps.

Related

How do I build the "composition" of components in the app?

The app has 2 levels of users, a regular user and an admin. You need to make a header component in which some information is the same for everyone, and some - only for admins.
There is a basic header component :
<div class="user-header>
<img src="logo">
<div class="user-header__links>"
...
</div>
</div>
'user-header__links' contains links, some of which should only be shown to admins. Also, the header must still have dropdown, that is available only to admins.
I see 3 possible solutions:
Make 2 different components, i.e. I have UserHeader for the user, and copy this code to a new component, edit as necessary and get AdminHeader, adding the necessary elements and links
in UserHeader, make props / slots for throwing additional content into it, and then adminHeader will look something like this :
<UserHeader links={some additional links for admins}>
<AdminDropdown/>
</UserHeader/>
Leave only AppHeader component and put elements in it for both users and admins, and just check the "admin" elements and show them if the user is also an admin.
I understand that in principle all the options are working, but to come to an understanding of which option is more convenient and practical somehow does not work. Also, if there are any articles regarding these points, I will be grateful for the links.
I'd say that the option 1 is just lots of unnecessary boilerplate, but only you can choose between 2 and 3, as it all depends on your proj structure, implementations and so on...
As with everything, app architecture is a lot about taste... I, personally, very much like the idea of "minimalism" here.
I think Conditional Rendering would help you solve this problem - here's React's doc page for it: https://reactjs.org/docs/conditional-rendering.html

Is there a way to compile react components to html before build time?

I have a function that takes dom elements and operate on them. It is called pageTransition, and it takes two div elements, and performs a transition animation from the one to the other.
function pageTransition(div1, div2){//do the transition}
for example i can call this function like,
pageTransition (document.body.querySelector("#div1"), document.body.querySelector("#div2"))
That is simple, but let us say I want to pass React class components as my div elements. And that isn't possible because react components are class's not html elements. One quick reminder, this react components in the end will be compiled to div elements with some content during build time. I know I could get around this by doing this
...//the react class
render(
return (
<div id="div1">...</div>//this will allow me to call the above function with the same parameters
)
).
But I was just wondering if there was a magic way to compile this react classes before build time, so rather than giving the id's to the returned div's I was wondering if I could do something like this pageTransition(compile(reactClass), compile(reactClass));
The solution will depend on your intended purpose for pageTransition.
However, there are three potential options you may want to look into:
Statically render a React component into html markup or a string: https://reactjs.org/docs/react-dom-server.html#rendertostaticmarkup
Render two div elements in html and use a React portal to manage what is being rendered in the those divs. This could potentially replace what you are doing in pageTransition. https://reactjs.org/docs/portals.html
Use a ref to access the DOM element that is built from the React component: https://reactjs.org/docs/refs-and-the-dom.html
If you explain what pageTransition does it might help me find a solution for you.

Component based clientlibs AEM

Is it better to split up clientlibs by components if it means more calls to the server?
I.e. using
<%#taglib prefix="ui" uri="http://www.adobe.com/taglibs/granite/ui/1.0" %>
<ui:includeClientLib categories="mqd.component.accordion" />
in the <component>.jsp instead of compiling all the CSS in a single stylesheet.
From what I know, this is more of a decision based your use case, there is no one approach which fits all the scenarios -
Loading CSS at component level
When you load CSS at the component level, it is not available in the HEAD section when the page rendering process kicks off. It will only render your component CSS when it encounters it somewhere in the body tag.
Conditionally loading CSS based on the component is not available by default, you would have to write custom logic to achieve this.
From this post,
One way to achieve this is to intercept that behaviour. Use a filter
and buffer all data written to the output buffer in memory. Then you
can render safely all components and if you encounter your special
component you can set a flag in the request attributes. The filter can
then check for these attributes, change the buffer accordingly and
then send everything out. That approach is a bit risky, because it
can consume a lot of memory. And it changes the rendering performance and behaviour of your page. But it might be worth a try.
Also, with component level CSS, you would have to ensure the styles
for a component don't affect styles for another component, i.e. you
would have to use narrow selectors to do this and ensure you don't
break anything else in the process.
Also, with component level CSS, you would have to ensure the styles for a component don't affect styles for another component, i.e. you would have to use narrow selectors to do this and ensure you don't break anything else in the process.
Other approaches
Using page components - If you have a component which has a lot of styles and you don't want this to get loaded on every other page, you can look at using page components(different templates) to achieve this. Each page component can load a different group of clientslibs based on its use.
Using deferred clientlibs - If your layout constantly changes and you’re worried about how big your clientlibs file has become, deferred clientlibs might be a better option. Example from the link listed below -
… [Navigation component logic]
<ici:js-defer>
<cq:includeClientLib js=”icidigital.components.navigation”/>
</ici:js-defer>
[Navigation component end]
… [Sitemap component logic]
<ici:js-defer>
<cq:includeClientLib js=”icidigital.components.siteMap”/>
</ici:js-defer>
[Sitemap component end]
becomes…
<div class=”footer” />
<script type=”text/javascript” src=”path/to/programmatically/combined/deferred/clientlib.js”></script>
</div>
Whatever approach you take, ensure caching, page load times, maintenance, performance, etc are taken into account.
Further read
Best approaches to clientlibs in AEM
CSS best practices in clientlibs

ReactRouter route render component to container element

My issue here is that I need to render separate route components to elements created by the backend. It's irregular I'm sure. Essentially I'm starting with an html document and need to render route components to particular elements in the dom.
Example:
If I have four components that each need to be rendered to a pre-generated element.
<body>
<div id="elone" />
<div id="eltwo" />
<div id="elthree" />
<div id="elfour" />
</body>
Now I need to render my respective components to each of those elements. The issue is that if I call ReactDOM.render within the component it doesn't recognize the router, and it doesn't appear that route has anyway to render to a particular element.
Note: I cannot unfortunately write the document within the JS, it has to be pre-generated. I don't need this to be done through react router if there are other solutions, but the components must recognize the router.
I hate answering my own questions, it makes it seem like no one is really answering questions here.
Anyhow the solution is to use ReactDOM.createPortal instead of ReactDOM.render within the components. Make sure to render the component with the router to an element outside of the container that you want to portal your subcomponents to otherwise you'll obviously clobber the elements that your portals are pointing to.

VueJS - Render dynamically passed template in component

I am using VueJS 2 to build a drag-and-drop layout builder. One of the requirements of that project is to be able to have some components that will allow for custom content to live inside (they will be just a wrapper around that content). And to be really concrete, I am trying to pass in and render another drag-and-drop zone which is implemented in a draggable component.
Basically, I want to pass a VueJS template to the component via a prop and have that template rendered inside of the component. This is necessary because I do not want the UI to limit the needs of the developer and therefore need this to be really extensible.
In the following trivial example I would like the "ui-element" to render the content prop inside of it and use the other prop as a data input.
<ui-element
:content="<draggable :name="contentData"></draggable>"
contentData="col1"
>
</ui-element>
Since just outputting the template will escape it, and v-html directive will treat it as regular HTML and not a template I am lost, not really sure how to get this done.
I spent about an hour or more googling but no luck. Which leaves me to three options:
1) I'm the first one to need this complex use case (unlikely)
2) Doing this is stupid on so many levels that no-one even bothered (if so, please let me know how to get this result in a smarter way)
3) There is a special uber-cool JS term for this which I simply do not know and that made my search attempts futile
You'd want to use slots instead.
In your ui-element component, define a slot like so:
<template>
<div>
<slot name="content"></slot>
</div>
</template>
Then you could pass in the draggable component like so:
<ui-element contentData="col1">
<draggable :name="contentData" slot="content"></draggable>
</ui-element>
Here's a very basic fiddle example of a slot.

Categories

Resources