Can we add events on react fragment? - reactjs

In my case, I have to wrap up the content in the parent component without adding extra div element to the DOM. So, I wrapped the element with the react fragment. I got a use case to add the native browser event to the react fragment, Is that even possible?

Short answer, no, you can't add events on React Fragments. There is a detailed discussion over here, but as such, I don't think React Fragments will be supporting event handlers in the near future.
You may convert the your React Fragment (from <> </>) to a div element instead, and attach events to them.
return <div onClick={() => handleClick()}> </div>;

You can't add events on react fragment.
you can only add key only to react fragments like
<React.Fragment key={id}>
.....
</React.Fragment>
not with this
<key={id}>
.....
</>

Related

Why infinite scroll pagination uses useState not using DOM append instead?

I have seen many tutorials and articles which use useState to store all the records on a state instead of using ReactDOM or something to add HTML elements.
For example, they keep previous data and merge with new data and after that set in a useState hook
return [...new Set([...prevBooks, ...res.data.docs.map(b => b.title)])]
I have 2 questions
Isn't it a performance problem to have all the records in the state and to print it in JSX by map? There may be millions of records.
If I want to add a React component to the end of a div#ID, what should we do in the pagination?
For example, I have this block code:
<article className="col-sm">
<div className="row client-home-header-post-article-row" id="BlogsPosts">
{posts.entries.map((item) => (
<BlogItem post={item} key={item.id} size={4} />
))}
</div>
</article>
And with an action function like const showMore, add another <BlogItem post={item} key={item.id} size={4} /> to the bottom of BlogsPosts ID (like e.append)
I saw this post Append component in React, he suggested without recommending to use ReactDOM.createPortal, but I tested it like this, and it does not work
ReactDOM.createPortal(
<BlogItem post={item} key={item.id} size={4} />,
document.querySelector("#BlogsPosts")!
)
The posts I saw:
Append component in React
Reactjs append an element instead of replacing
How do you append a React Component to an html element
How to append React components to HTML element using .append()
How can I append a React component to an html element i?
Using document.querySelector in React? Should I use refs instead? How?
Append Element to an Existing Element React
Thank you in advance
Isn't it a performance problem to have all the records in the state
and to print it in JSX by map? There may be millions of records.
It depends. A performant server should try to keep the metadata it returns to the browser for each book small. That is, each book object should try to to contain minimal information like a title, author, price, and thumbnail URL, not all the data that the database knows about the book. Something like this:
{
"title":"MyBook",
"author":"Jeff Bezos",
"price":19.99,
"price_unit":"USD",
"thumbnail":"https://websitename.s4-bucket.region.UUID-1234"
}
Reducing the amount of data will boost performance by making searching through this data faster on the browser. Each object of this size is also less than 500 bytes, so if you are obtaining 50 items at a time you're only retrieving 25KB data per request, which with modern speeds only takes a few milliseconds.
If I want to add a React component to the end of a div#ID, what should
we do in the pagination?
You can use a useMemo hook which will update the BlogItem components you have rendered when the posts change. Something like this should work:
const blogItems = useMemo(()=>posts.entries.map((item) => (
<BlogItem post={item} key={item.id} size={4} />
)), [posts.length])
Then in your JSX just do this:
<article className="col-sm">
<div className="row client-home-header-post-article-row" id="BlogsPosts">
{blogItems}
</div>
</article>

Why is nextjs persistent layout re-rendering all the time?

I am trying to follow the persistent layout examples as presented on the official docs and Adam Wathan's article here.
This is what I know so far:
I am aware about React's reconciliation process. I know that if react realizes the virtual dom tree of a component hasn't changed, then it wont update the html dom elements of that tree/component. Article I used to better understand some of these concepts
React rerenders a component if its state changes. If a prop changes, it should not? Or is there an assumption that a prop is implicitly considered a state?
If a parent re-renders, then children will be re-rendered.
I am aware (though still need to learn/readup) on React.memo. Once I do, I plan to utilize that as well. I am vaguely aware that it caches the component for the given input (props) and if props doesn't change, it returns the cached component.
Based on the above, I would say that persistent layout works because the layout used in _app.js is provided the page as its prop (children). Since layout's own state doesn't change, layout shouldn't get re-rendered. However, that is not what I am noticing, and hence this long winded question.
Just so I am clear, when i say re-render, I am talking about React recreating the virtual dom for the component rather than repainting the html dom. My issues are with the former and not the later.
What I am seeing is that every time I click on the "Profile" link (even if I am already on the same page):
The entire layout (including top nav bar, icons, search bar and links) all re-render.
I see the console log messages being printed for each of them.
I used the "Profiler" tool and it too shows me all the components rerendering.
I thought that a persistent layout meant that it wouldn't be re-evaluated all the time? The printing of console logs indicates that the component is being re-evaluated every time. I know React.memo would avoid this entirely, but then what exactly is "persistence" about this? What am i missing or failing to understand about persistent layouts in this case?
What I have looks like this:
/pages/profile.js (and similarly /pages/anotherPage.js)
function sampleProfilePage (props) = {
return (
<div>I am on profile page</div>
);
}
export default sampleProfilePage
_app.js
function MyApp({Component, pageProps}) {
return (
<SimpleLayout>
<Component {...pageProps} />
<SimpleLayout />
);
}
SimpleLayout.js
function SimpleLayout ({children}) {
return (
<>
{console.log("simpleLayout re-rendered")}
<SimpleTopBar />
<main>{children}</main>
</>
);
}
export default SimpleLayout;
SimpleTopbar.js NOTE: css can be ignored. Its present in .module.css file.
function SimpleTopBar () {
return (
<div className={classes.container}>
{console.log("SimpleTopBar re-rendered")}
<Link href="/profile">Profile</Link>
<IconCircle />
<SearchBar />
<IconSquare />
<Link href="/anotherPage">Another Page</Link>
</div>
);
}
export default SimpleTopBar;
IconCircle (and similarly IconSquare) NOTE: ignore css again. Also, I recently became aware that defaultProps are deprecated. I am in the process of updating/writing inline default values.
export function IconCircle (props) {
return (
<svg xmlns="http://www.w3.org/2000/svg"
className={props.name}
... rest of svg data ...
</svg>
);
}
IconCircle.defaultProps = {
name: classes.iconCircle
}
SearchBar.js NOTE: this is taken straight from Adam's code in order to try and compare what I was seeing.
function SearchBar (props) {
return (
<div className="mt-2">
{console.log("Search bar rendered")}
<input className="block w-full border border-gray-300 rounded-lg bg-gray-100 px-3 py-2 leading-tight focus:outline-none focus:border-gray-600 focus:bg-white"
placeholder="Search..."
/>
</div>
);
}
export default SearchBar;
Disclaimers:
I am a backend engineer and just starting to learn React and Nextjs. Its is highly possible that my design and understanding is limited or not exactly what one might expect in the industry/professionally. So, if there are some general practices or commonly known knowledge, please do not assume that I am following that or aware of it. Its part of the reason why I pasted entire functions. I am still reading up on various pages/questions and trying various things to rule things out, or understand better what is being shown/told to me.
Thank you in advance for the patience to read this question, and sorry for its length.
You have a pretty good understanding of what's happening.
All pages in Next.js depend on _app - it rerenders because of pageProps or more likely Component prop changes - forcing the children to rerender.
The layouts will 'persist' between pages - the children should rerender on a route change but, components that are still on the page should keep their state.
i.e. a search input in the layout should keep its search term on route changes to another page with the same layout.
The only way not to rerender during route change is to use shallow routing . But it doesn't really route - it just allows you to add query params to the current route (can't change pages or it will use standard routing).
As you mentioned, you can use memo on some of your components to prevent rerendering, but only use it when you know you need it and use it wisley.
Lastly, rerendering is also part of React and virtual DOM manipulation, I wouldn't worry about it too much until it becomes a problem.

Why is onClick not shown in Element?

This is my React code:
<button
className="show-all"
onClick={() => { console.log("button clicked");}}>
button
</button>
This is what rendered in the browser:
<button class="show-all">button</button>
I am so curious: Why is the onclick missing? This will not affect the function, but I just cannot see the onclick name.
The following code has the same problem.
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
function shoot(){
console.log("shoot")
}
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
class ShowAlert extends Component {
showAlert() {
alert("I'm an alert");
}
render() {
return <button onClick={this.showAlert}>show alert</button>;
}
}
ReactDOM.render(
<>
<button onClick={() => console.log("good")}>
Click 1
</button>
<button onClick={shoot}>
Click 2
</button>
<button onClick={handleClick}>
Click 3
</button>
<ShowAlert />
</>
,
document.getElementById('root')
);
And I don't know if this small uncomfortable point is worth discussion.
React implements a synthetic events system that brings consistency and high performance to React apps and interfaces. It achieves consistency by normalizing events so that they have the same properties across different browsers and platforms.
A synthetic event is a cross-browser wrapper around the browser’s native event. It has the same interface as the browser’s native event, including stopPropagation() and preventDefault(), except the events work identically across all browsers.
It achieves high performance by automatically using event delegation. In actuality, React doesn’t attach event handlers to the nodes themselves. Instead, a single event listener is attached to the root of the document. When an event is fired, React maps it to the appropriate component element.
Resource - https://blog.logrocket.com/a-guide-to-react-onclick-event-handlers-d411943b14dd/
As pointed out in the comments to the question and the previous answer, React does not render events in the DOM, so they are not shown in the HTML elements.
I would like to add that if you just want to inspect the React events you can use devtools for that.
For example, for Firefox, MDN provides nice instructions on how to inspect events in devtools, and here is an example for Chrome.
This feature is what I like most, unlike Angular. This is not just about listeners, but also props. React handles the DOM virtually, so everything works virtually than having them in real DOM.
I had the same question in previous days and I noted: why is it so? Just continue reading for what I found specific in React.
You might also surprise why className renders class in the HTML? I mean, you might confuse why class is shown, but not onclick?
In JavaScript, class conflicts with the keyword class and it has a different name, i.e., className. React JSX just works like JavaScript and it binding the class in HTML.
Similar to className, there is htmlFor to the for attribute. You can see for in the rendered HTML like you see class for className.
So, when a React element is rendered in the browser it will only show the HTML attributes, but not React props.
There is onclick in JavaScript and onClick is specific to React (however, React internally transforms it to onclick as pointed out in other answer - synthetic event) and thus onClick is not shown in the DOM when it renders. React updates and works in a virtual DOM.
The only thing you need to note that - do provided props match a DOM attribute case sensitively? If yes, it will show in rendered HTML. Otherwise, No.
I hope, you have now a better understanding about these.
If you would like to see attached listener and props, etc. then you can use React devtools.

ReactDOM.render does not re-render the 2nd element on the list

im having problem with ReactJS, i
on index.js i have:
ReactDOM.render([<App />, <Footer />], document.getElementById('root'));
the problem is that Footer needs to add an 80px padding from the bottom only on certain pages
so on the render method i do
<div>
{isMobile && window.location.pathname.startsWith('/summary') &&
<div style={{height: 80}}></div> }
</div>
but it doesn't re-render when window.location.pathname changes,
i move around the web app and it doesn't change only when i hit F5 it renders correctly on that page.
i tried using events on window but they're aren't invoked as well...
window.addEventListener('locationchange', function(){
console.log('xxxxxxx location changed!');
})
window.addEventListener('hashchange', function(e){console.log('xxxxxx hash changed')});
window.addEventListener('popstate', function(e){console.log('xxxxxxx url changed')});
how i can make it re-render? or make Footer work as React component that can render ?
This is a common problem!
Out of the box, React is configured to operate on a single page (see Single Page Applications), which basically means it deletes what's shown on screen and renders new information when an update is required.
Naturally, simulating the routing behavior that's observable for non Single Page Apps is a little more difficult - check out React Router, which is a library created to tackle this exact issue.

Can one React component render by 2 classes?

Can one React component render by 2 classes? Just like I did in the picture.
I tried the above. It gives me another error Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of "Groups".
The button component Im using in Groups method(Groups.jsx) like this way.
const Groups = (props) => (
<div className = 'panel'>
<h2>Groups</h2>
<button >Get Groups</button>
<div className = 'group-list'>
{props.groups.map((group) =>
<GroupsEntry name = {group.name}
members = {group.members}/>
)}
</div>
</div>
);
Do you guys have any idea about this? Thank you
I will try to clarify a little.
You can render a component from whatever parent component you want.
By in the case of your picture, what is telling you that the first component in tree, was App.js, and then App.js rendered Groups.js component, and Groups.js rendered your actual component.
In the same page, the warning you are seeing about using "key" is because you need to set a unique key value for each element that you are rendered as a list, a repeated item. This is because the internal react work to compare if it has to rerender again your component needs it. You will have performance problems (not in an easy example...) if you dont add it. Normally you use the id of the object you are rendering.
I hope i clarified a little.
Yes, a component can be rendered as many times as you would like. The issue is that you are mapping over an array and returning an element. React requires that you put a unique key prop on these elements that ideally are consistent between renders.
You can try to update your code to be something like the following:
const Groups = props => (
<div className="panel">
<h2>Groups</h2>
<button>Get Groups</button>
<div className="group-list">
{props.groups.map(group => (
<GroupsEntry key={group.name} name={group.name} members={group.members} />
))}
</div>
</div>
);
This is assuming group.name is unique. If you have a unique identifier (eg: group.id) that would be ideal.
For more examples and why this is necessary you can checkout the official docs: https://reactjs.org/docs/lists-and-keys.html

Resources