Correct way to hide components in React.js - javascript

Say you are passing a prop called show to a component. If the prop value is true, you should render the full component normally. If it is false, you should not display anything.
You can do this two ways.
return null in the render method of the component.
apply a CSS class containing display: none attribute to the component's DOM element.
Which ones is the correct or the preferred way?

I do not think there will be any definite answer for this question.
Each approach has its benefits and drawbacks.
With CSS you have:
it might work faster
no need to think about restoring child control states if control is shown again.
With returning null:
the total rendered DOM might be considerably smaller. This is important if you have many such components that might be hidden.
there will be no collisions in rendered html. Lets say you have tabular view. Each tab is its own complex form with many child controls. If you have some raw javascript/jquery/whatever working with their ids/classnames etc. - its quite hard to ensure each tab/form has unique ids, unless you do not render them.
From my point of view the decision will be based upon the structure of your control. If it have complex structure with many nested children and you do not have any means of restoring their states when switched on again - go with CSS, but I would say this is a short term solution for quite simple controls only. In all other cases I would go with not rendering a component.

If you think you would need to display the component again, during that page life, then I would recommend using css way, as the impact on DOM manipulation would be less in that case. In some other cases probably returning null would be more helpful.

For the most part, your two solutions are interchangeable. They both "work" fine.
I would warn against preemptive optimization in choosing which of these methods to choose. If you do need to eventually modify your code and try the other method, this is an absurdly simple swap to make and shouldn't be an obstacle. So don't worry about it until there's a reason to worry about it.

I'm the OP.
If components are hidden depending on the screen size, CSS media queries and display: none works the best if the app is pre-rendered using something like react-snap. This is because, if the pre-rendered device and the viewing device don't match, the layout would change when the app rehydrates if the component hiding logic is in JS.
Related to that, we need to be careful that even though the component is not "shown" with CSS display: none, the component is still there and if there are effects, they will still fire.

Related

Convenient way to get input for puppeteer page.click()

Challenge
When using puppeteer page.click('something') one of the first challenges is to make sure that the right 'something' is provided.
I guess this is a very common challenge, yet I did not find any simple way to achieve this.
What I tried so far
In Google Chrome I inspect the element that I want to click. I then get an extensive element description with a class and such. Based on an example I found, my approach is now:
Take the class
Replace all spaces with dots
Try
If it fails, check what is around this and add it as a prefix, for example one or two instances of button.
This does not exactly feel like it is the best way (and sometimes also fails, perhaps due to inaccuracies from my side).
One thing that I notice is that Chrome actually often seems to give a hint hovering over the thing I want to click, I am not sure if that is right but I also did not see a way to copy that (and it can be quite long).
If there is a totally different recommended way (e.g. Looking in the browser for what the name roughly is, and then using puppeteer to list all possible things), that is also fine. I just want to get the right input for page.click()
If you need an example of what I am trying: If you open this question in an incognito tab, you get options like share or follow. Or if you go to a web shop like staples and want to add something to cart.
When using puppeteer page.click('something') one of the first challenges is to make sure that the right 'something' is provided.
Just to be clear, "something" is a CSS selector, so your question seems to reduce to how to write CSS selectors that are accurate. Or, since Puppeteer offers XPath and traditional DOM traversals, we could extend it to include those selection tools as well.
Broader still, if there's a data goal we're interested in, often times there are other routes to get the data that don't involve touching the document at all.
I guess this is a very common challenge, yet I did not find any simple way to achieve this.
That's because there is no simple way to achieve this. It's like asking for the one baseball swing that hits all pitches. Web pages have messy, complex, arbitrary structures that follow thousands of different conventions (or no conventions at all). They can serve up a slightly or completely different page structure on any request. There's no silver-bullet strategy for writing good CSS selectors, and no step-by-step algorithm you can apply to universally "solve" the problem of accurately and robustly selecting elements.
Your goal should be to learn the toolkit and then practice on many different pages to develop an intuition for which tools and tricks work in which contexts and be able to correctly discern the tradeoffs in different approaches. Writing a full guide to this is out of scope, and articles exist elsewhere that cover this in depth, but here are a few high-level rules of thumb:
Look at context: consider the goals of your project, the general structure of the page and patterns on the page. Too many questions on Stack Overflow regarding CSS selectors (but also in general) omit context, which severely constrains the recommendation space, often leading to an XY problem. A few factors that are often relevant:
Whether the scrape is intended to be one-off or a long-running script that should try to anticipate and be resillient to page changes over time
Development time/cost/goal tradeoffs
Whether the data can be obtained by other means than the DOM, like accessing an API, pulling a JSON blob from a <script> tag, accessing a global variable on the window or intercepting a network response.
Considering nesting: is the element in a frame or shadow DOM?
Considering whole-page context: which patterns does the site tend to follow? Are there parent elements that are useful to selecting a child? (often, this is a distant relationship, not visible in a screenshot as provided by OP)
Consider all capabilities provided by your toolkit. For example, OP asked for a selector to close a modal on Stack Overflow; it turns out that none of the elements have particularly great CSS selectors, so using Puppeteer to trigger an Esc key press might be more robust.
Keep it simple: since pages can change at any time, the more constraints you add to the selector, the more likely one of those assumptions will no longer be true, introducing unnecessary points of failure.
Look for unique identifiers first: ids are usually unique on a page (some Google pages seem to scoff at this rule), so those are usually the best bets. For elements without an id, my next steps are typically:
Look for an id in a close parent element and use that, then select the child based on its next-most-unique identifier, usually a class name or combination tag name and attribute (like an input field with a name attribute, for example).
If there are few ids or none nearby, check whether the class name or attribute that is unique. If so, consider using that, likely coupled with a parent container class.
When selecting between class names, pay attention to those that seem temporary or stateful and might be added and removed dynamically. For example, a class of .highlighted-tab might disappear when the element isn't highlighted.
Prefer "bespoke" class names that seem tied to role or logic over generic library class names associated with styling (bootstrap, semantic UI, material UI, tailwind, etc).
Avoid the > operator which can be too rigid, unless you need precision to disambiguate a tree where no other identifiers are available.
Avoid sibling selectors unless unavoidable. Siblings often have more tenuous relationships than parents and children.
Avoid nth-child and nth-of type to the extent possibe. Lists are often reordered or may have fewer or more elements than you expect.
When using anything related to text, generally trim whitespace, ignore case and special characters where appropriate and prefer substrings over exact equality. On the other hand, don't be too loose. Usually, text content and values are weak targets but sometimes necessary.
Avoid pointless steps in a selector, like body > div#container > p > .target which should just be #container .target or #container p .target. body says almost nothing, > is too rigid, div isn't necessary since we have an id (if it changes to a span our new selector will still work), and the p is generic--there are probably no .targets outside of ps anyway.
Avoid browser-generated selectors. These are usually the worst of both worlds: highly vague and rigid at the same time. The goal is to be the opposite: accurate and specific, yet as flexible as possible.
Feel free to break rules as appropriate.

Creating a React component and states from regex string matches

I'm moving the frontend of a project I'd written primarily with php and jquery over to react as a learning exercise. So far it just seems to be making everything a bit more convoluted but I'm hoping I'll see the benefits soon. Right now it's just good to be familiarising myself with something far more current than what I was using. But I digress...
There's one particular situation I'm translating at the moment that feels simple to do in jquery but feels like I'm having to choose between a bunch of cumbersome or not-recommended solutions with react, such as dangerouslysetinnerhtml
A user can input their own list, as raw text, which the app parses using regex to highlight quantities and items, illustrated above as highlighted by rose and green. New lines are parsed as list elements, highlighted in peach. The parsed quantities can be scaled using a range input, shown above the list. The example UI shows an example after parsing a raw string of text.
Previously - jquery
When I was using jquery I replaced regex matches with <span> elements containing data attributes to create new elements I could target. The quantity scaling function in the app could now reference the original quantity of a list item at any time using a data attribute.
e.g. I need 10 cars is parsed to become <li>I need <span class='highlight quantity' data-count='10'>10</span> <span class='highlight item' data-item='cars'>cars</span></li>
With jquery, whenever the input range is dragged, I just target all elements on the page that have the quantity class, reference their data-count and replace the span value with the current range value multiplied by that data-count. This worked well.
Now - React
I'm getting my head around react components. Referencing the illustration, above, I have a component for dialogs (as there will be other dialogs too), a component for the range input of dialogs, a component for the list, and a component for list items.
As before, when I drag the input range, I want the quantities on the page to change to reflect the new scale set by a user. When picking up react I became familiar with component states and props and thought these would solve my problem beautifully. If I had a scale state I could pass it through the components and anything in the hierarchy could reference it. As I understood it, the hierarchy was important and it was important to hold the state at the top so that lower-level components could be 'fed' it, if that's a good way of putting it. This appeared to be best practice.
But I'm having a tough time getting it to jump through hoops. Maybe I've misunderstood?
Two uncertainties
1
If I've understood the hierarchy of states correctly, I'm setting the state initially inside the App() function, like so:
function App() {
const [scaleValue, setScaleValue] = useState();
const handleScaleChange = (childData) => {
setScaleValue(childData);
}
return (
<React.Fragment>
/~~~/
<UserList rawstring={userText} scale={scaleValue} />
/~~~/
<Dialogs scale={scaleValue} setscale={setScaleValue} parentCallback={handleScaleChange}/>
</React.Fragment>
);
}
But I must use a callback function to change the state as the dialog range I'm using is nested a few levels down in components - passing it back to the state in the parent App() function and then back down to all the nested components using props. It felt much easier to just target elements with a matching class name in jquery and I'm not yet seeing the advantage of having components using states. I thought being able to target list item components with quantity states would have advantages in React that were more apparent.
2
Perhaps the main thing that has me stumped on how to proceed. In jquery, when I was parsing a raw string provided by the user, into html that I could target with specific classes, I just used some regex functions to return html that could be inserted into the dom. Example of the html is per the earlier example:
I need 10 cars is parsed to become <li>I need <span class='highlight quantity' data-count='10'>10</span> <span class='highlight item' data-item='cars'>cars</span></li>
With react, I parse the same string to the same html fine, but I've no idea how to handle it from there, logically? If I return it and insert it, it is treated as raw text and renders the html tags on page. I can use dangerouslysetinnerhtml and it shows fine, but I've loud and clear got the message that this is heavily discouraged. I want to use best practices.
In fact, I likely don't want to be returning quantities wrapped in targetable classes. I gather that I want to be able to assign states to a list item component. I have absolutely no idea what's the best approach (logically) to do this with react. I could return an array from the regex parsing but this feels needlessly complex compared to replacing a matched sub string with a wrapped version of itself.
I feel at this point I may be approaching the translation wrong (or my understanding of using the component system and states) as this feels so much more convoluted than the jquery approach I was using.
not-recommended solutions with react, such as dangerouslysetinnerhtml
That's not what dangerouslySetInnerHTML is about. It's about the fact that an unsanitized string containing HTML/JS could pose a security threat (XSS mostly). In other words, in React you have to explicitly use dangerouslySetInnerHTML if you need to be unsafe, but it's your responsibility to protect yourself, hence the name. Doesn't mean it's not recommended, just tells you to be extra careful.
the hierarchy was important and it was important to hold the state at
the top so that lower-level components could be 'fed' it, if that's a
good way of putting it.
Indeed, at first it might look overly complicated for no good reason. Today.
A few months from now if you'll have to go through that code again, or worse, if someone else will have to, this structure enforcing rules and structure makes it far more easier to make changes. You can simply right click on the "callback" function and "go to definition" in your IDE of choice and see where it's defined, instead of hoping it's not hidden in some JS file or relying on search when the function is named "handleClick" in a project with one thousand click handlers.
It felt much easier to just target elements with a matching class name in jquery
Of course it was, anyone with minimal experience in a large scale project knows this. There always are trade-offs. You need to judge if it makes sense to loose simplicity for the sake of maintainability based on the scale of the project.
With react, I parse the same string to the same html fine, but I've no idea how to handle it from there, logically?
You are mixing parsing with generating HTML. You were parsing the string and generating HTML. With React you have to parse the string and generate JSX. If your code was separating these two concerns then it would have been a lot clearer what the difference is.
Again, if you are the only one working on this and know you'll never touch it again, why bother separating these two parts? On the other hand if you do expect to touch that piece of code later or know there will be other people working on it then the smart option would be to split it so that you can properly unit test it.
I can use dangerouslysetinnerhtml and it shows fine, but I've loud and clear got the message that this is heavily discouraged. I want to use best practices.
No, that's not the point. If you use dangerouslySetInnerHTML then how are you going to interact with those highlighted numbers? document.querySelectorAll? That is indeed against the purpose of React. I think my answers above make it clear what a more suitable approach would be.
feels needlessly complex compared to replacing a matched sub string with a wrapped version of itself.
And it is because you don't understand why someone would use React. You think React is a replacement for jQuery and it is not. It is a way of writing JavaScript applications so that you don't end up with a pile of code no one can follow. Which is a problem that only exists if you eventually end up with a lot of code. Your application has what, 100 lines of JavaScript? Why are you even using jQuery?
My advice is:
Understand that people that make deliberate choices don't choose React because it's fashionable but because it solves some problems.
Figure out what those problems are. I've listed a big one, which is maintainability and that structure and separation of concerns are part of the solution.
Decide if you care about any of the problems React helps solve in any of the projects you work (or will work) on.
If you do care about these problems then put yourself in the appropriate state of mind. React is not meant to replace jQuery, find a project that would benefit from using React.
Understand that React is not the one and only tool you'll ever need.
Some more advice:
definitely have a look at useReducer and then (if you need the extra juicy bits) Redux for state management. All beginner tutorials try to stay away from them but IMO React is an empty shell without proper state management.
React is a clean way of turning state into HTML/CSS. The philosophy is that any action (e.g. a click on a "add a new row" button) should produce a state mutation that translates into manipulating some data, NOT the DOM. Your JSX is one representation of that data! And React does a great (fast) job at manipulating the DOM to reflect the new JSX representation. So start thinking your application in terms of input-output, data structures and actions/reducers that manipulate these data structures.
force yourself to unit test (or, better, TDD) your actions and reducers. Completely decoupled from JSX and DOM! Your entire application logic should be testable in Node CLI. This to me (that you can completely separate logic from presentation) is a major win (and is the base of React Native too).
have a look at https://storybook.js.org/ - this one is another one of those fantastic tools (not only for React) that will completely change your development experience.
be wary of using "component libraries". Most "complicated" things turn into child's play when you really understand how to design them correctly.
be prepared to spend 3x the time you spent before on implementing really simple stuff for a while, until you familiarize yourself with the core concepts and philosophy.

Approaches tested for accommodating RTL on existing angular application

If you have an existing angular application, that already have localization working (i.e text load in different languages) if one of those is RTL direction (Hebrew/Arabic etc) how would you go about writing the code for that?
Remember it's not enough to change the dir="rtl" on those warpper/html. For example elements in nav bar have to be mirrored and floated to right.
Popover (when you hover elements) need to change direction and so the list goes on.
Approaches tested for accommodating RTL:
1.
Setting text direction BEFORE we load the app in our app-load module (Using app_initializer)
In that function we can set the dir attribute on the HTML and lang
Based on the user's local language
Later when we bootstrap our angular application we can look into that html attribute
This (1) I like and want to keep doing.
2.
Using only css/less/sass to change the looks of the site after we have 1 working
Those styles (as we want) will only get applied for languages with rtl direction
But when we tried to rotate (mirror) nav links (in header) and change popover directions things got very tricky.
The order of elements in the html as well as the styles need to change, and for some components the changes were significant, therefore we tried approach number 3.
We can still leverage using this approach with the next ones (combine them) so this is still useful.
On more specifics what didn’t work with less was the use of dispaly: flex on a wrapper elements
With combination of :nth-child(i)
Selectors with order: j;
To rotate elemenst in nav bar
Only things like float: right were successful
Also tested some
-webkit-transform: scaleY(-1);
With combination of display:inline-block;
3.
If we could have a simple way to dictate which templateUrl we load into the components
We could then have for A.compoenent one a.html template (default ltr direction) and another
A-rtl.html based on a condition.
See fore ref:
Angular 2 dynamic template url with string variable?
Essentially splitting the templates into 2 but the HUGE benefit would be that we can have the .ts code once
This will be greatt but I can't get this to work.
Even if it’s possible it seems that it will prevent AOT compilation. (or not?)
See for ref: (old post but still relevant)
https://blog.lacolaco.net/post/dynamic-component-creation-in-angular-2-rc-5/
The angular official documentation approach
https://angular.io/guide/dynamic-component-loader
This is working! The issue is that this isn’t exactly what we want. In this approach we load separate COMPONENTS into a placeHolder and not separate TEMPLATES
4.
This approach is to use *ngIf on the template wrapping our ltr (current template) with
And adding a seperate one below it with
There will be some duplication in this case, but this isn’t really code (it’s HTML) it’s simply markup, plus like this we have much more control on how things look and where, and if we need to use for example popover-rtl component instead of the current popover (which again isn’t currently compatible with RTL) we can EASILY do so.
In this approach there are several simple approaches to determine for every component if we are on ltr or rtl text direction (for the ngIf)
In short is using a baseComponent, or a service.
Note: both approaches 3,4 can use what we did in 1 and 2.
Any suggestion on how to get approach 3 working?
Ideally I can get a condition to determine which templateUrl I should load for the component so the the code in .ts is there for both and only markup is different.
Please suggest on Annular 6+ version if possible.
P.S been using this site for over 10 years almost every day and that is my first questions, thumb me up please :)
Thanks!
although a long time passed from your posting:
create a base component, that will hold all the logic.
create as many components per your liking (one for RTL, one for LTR etc). each component will inherit from the base component. each component will have it's own HTML template, styles etc.
you select which component to show, via routing, ngIf or whatever suites you needs.

Render all possible elements or render on request

So I have an app that has a right sidebar whose visibility is toggled via a button. In that sidebar there can be one of several things [at a time] - chat, help, search. I was looking at some plain HTML from apps which have a similar feature and noticed that they have all nodes rendered, but are just hidden via CSS.
Since I need to do the same thing, I was thinking whether this would be a good idea to do with React. But then I realized that React elements have a state which when updated calls the render method. So I can use the state to store both whether the sidebar is opened, and what is inside the sidebar.
Is that the React way of doing things? Is it better to have all nodes rendered even if they are not visible, or is it better to have the nodes rendered on request via state changes?
My feeling is that only rendering what is visible would be the more standard React way, but in this case, this is mainly a performance decision. If you render everything and just toggle visibility with CSS, the first render will take longer (but the time difference may not be relevant or even noticeable). If you render only the part that's visible, React needs to do a small rerender every time the sidebar content changes. (This may also not be noticeable time.)
My recommendation would be to try both, if you want to test the performance. But I think you won't go too wrong either way.

Swap out views with Backbone?

I've looked around but have yet to find a great solution the the following problem:
I have a Backbone View tied to an el on the page that is a container element for what I'll call a "sidebar" in the traditional sense (for explanation's sake). This sidebar element's inner-html needs to change completely depending on the route. However, the position on the page never changes, and will always fill this container.
Now, for an initial prototype, I had a 1:1 relationship between this container and the view placed in it (I only coded up one route). Now however, said view needs to change based on the route as I've mentioned.
Being that these different views have entirely different html markup, response to events, etc... I had thought that I'd make sense to have a higher level view that'd swap in sub-views. Of course, one solution that would work would be to handle everything in the same view, but the necessary logic would be cumbersome (and pretty damn unwieldy).
Currently, here's what I'm thinking (and have partially implemented):
Have a top-level view for this page element.
Depending on the route, swap in the necessary sub-view.
These subviews are rendered with dust.js, where the .html template for just this component on the page is lazy-loaded via AJAX, compiled, and cached. Subsequent renders just consist of calling the cached "compiled" function with a new context.
Additionally, I was going to initialize and cache each of the subview Views within the top-level View, such that I'm only instantiating, setting up event handlers, etc.. once.
Then, depending on the route, look up the associated subview View (cached), and swap it in in-place of the current view.
Now, as I've mentioned, I have this mostly coded up and... semi-working. However, what I'm struggling with is how to have each of these subviews exist independently and handle the swapping, but keep all of the event handlers and current state to continuing to live whether the component is currently displayed or not.
Basically:
How to avoid completely destroying / re-instantiating subviews each time they're required. Maybe this operation isn't as expensive as I'm thinking it is and I should simply do the latter.
Being that the top-level View (the "manager", if you will) is tied to the container $el, how to swap in the subviews.
I'm sure there's a simple, elegant solution. I just haven't found it yet, unfortunately.
As far as point 1 is concerned I don't think it is too expensive to let the view be created each time.
For point 2 - I would recommend using Backbone.Marionette https://github.com/derickbailey/backbone.marionette. It has the concept of a Layout which lets you define different regions of your app and render/manage them individually.
I would recommend Backbone.Marionette not just for point 2 but for the way in which it allows you to manage interaction is in my opinion much better than standard Backbone.

Categories

Resources