React component closing tag - javascript

I'm new to React and I'm trying to figure out the purpose/use of <MyComponent></MyComponent> vs <MyComponent />. I can't seem to find information on anything except self-closing tags.
I've created a basic tab scroller as a JSFiddle using the self-closing <MyComponent /> and subsequent props, and I'm wondering if there's a better way to write in React than what I've done.
class TabScroller extends React.Component {
render() {
return (
<div className="tabScroller">
<div className="NavList">
<TabNav handleClick={this.handleNavClick} />
<TabList
tabs={this.state.tabs}
activeTab={this.state.activeTab}
scrollPosition={this.state.scrollPosition}
handleClick={this.handleTabClick}
/>
</div>
<TabContent content={this.state.tabs[this.state.activeTab].content} />
</div>
);
}
}
// ========================================
ReactDOM.render(
<TabScroller />,
document.getElementById('root')
);

In React's JSX, you only need to write <MyComponent></MyComponent> when the component has child components, like this:
<MyComponent>
<Child />
<Child />
<Child />
</MyComponent>
If there is nothing between <MyComponent> and </MyComponent>, then you can write it either <MyComponent/> or <MyComponent></MyComponent> (but <MyComponent/> is generally preferred). Details in Introducing JSX.
Just as a side note, you'd access those children in your component via the special props.children property. More in JSX in Depth: Children in JSX.
Note that this is very much not like HTML or XHTML. It's its own (similar) thing with different rules. For instance, in HTML, <div/> is exactly the same thing as <div>: A start tag, for which you must eventually have an end tag. Not so JSX (or XHTML). The rules for HTML are that void elements (elements that never have markup content, such as br or img) can be written with or without / before > and they never get an ending tag, but non-void elements (like div) must always have an ending tag (</div>), they cannot be self-closing. In JSX (and XHTML), they can be.

The purpose of self-closing tags is simply the fact that it is more compact. This is especially useful when said component doesn't have any children that you typically wrap around a parent.
So usually for leaf components (i.e compoents that do not have any children), you use the self-closing syntax. Like: <Component />. And even if it has props, you can do: <Component foo="bar" />.
However, remember that children is a prop, so you could technically do:
<Component children={<span>foo</span>} />
but I find it less readable and advise against it (read disclaimer below).
To summarize, these are equivalent:
<Component /> = <Component></Component>
<Component foo="bar" /> = <Component foo="bar"></Component>
<Component children={<span>foo</span>}></Component> =
<Component><span>foo</span></Component>
You can use whichever approach you prefer. Though praxis is to use the short-hand version when there are no children.
Disclaimer: While defining childen prop by its object key value will technically work, doing so is strongly discouraged as it disrupts the API as it is meant to be used. Use this version only if confident in what you are doing.

Related

How to change the styling of a component in another component ? React

First I apologize if this question has been answered elsewhere. I'm still learning.
Assuming we have a parent component that has children components inside of it, so :
in App.js:
<>
<Advertisement title="Free Shipping For Orders Above 150 USD ! " />
<NavBar />
<LandingSection />
<Featured />
<Explore />
<Shop />
<RecommendedVideos />
<AsSeenOn />
<Footer />
</>
Now, we all know that each component has it own css file, however, if I want to change specific CSS attributes/styles to fit with the new component and I just want it in this specific component, in our case it is App.js. What should I do ? any tutorials on this topic ?
Also ... What is the difference between using
import styles from './styles.css
className = {styles.someName}
and using
styled-components library ?
and most importantly, in professional/real-world apps, what method do developers use ?
Each component should use either css modules or styled component. That way style will be scoped to that component.
If you use plain css then it might clash with other components styles.

Fragments should contain more than one child - otherwise, there‘s no need for a Fragment at all react/jsx-no-useless-fragment

I am getting this error in the app.js file in my react project:-
Fragments should contain more than one child - otherwise, there‘s no need for a Fragment at all react/jsx-no-useless-fragment
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import NavMenu from './components/NavMenu';
export default function App() {
return (
<>
<Router>
<NavMenu />
</Router>
</>
);
}
I have been trying to find a solution but couldn't get one so can someone pls tell me how to fix this
Any help would be appreciated
I got the same error today due to the fact that I had ternary operator in the following manner:
<>
{isCheck ? (
<button
....
>
</button>
) : (
<div className={class}>
....
</div>
)}
</>
Whan I realized is that without the wrapping element it was not running as it is supposed to be.
My solution was just to replace the Fragment with div.
That made lint happy and the red flag disappeared.
React is not supposed to return adjacent elements, so if you just return one component or element there is no need for using <></> or <React.Fragment></React.Fragment> (these are equivalent).
You will probably encounter situations when you need to return 2 div elements one next to another (like siblings). In that case <></> will come in handy.
Your component is returning the equivalent to this:
<React.Fragment>
<Router>
<NavMenu />
</Router>
</React.Fragment>
<></> is shorthand syntax.
The fragment is for cases when you want to return more than one component or element as siblings. But because a component must only return one thing, we can use fragments to put a sort of "invisible wrapper" around two components to make it appear to be one.
Here is an example of when a component might like to use a fragment:
return (
<>
<Navbar />
<Router>
<Routes>
<Route index element={<Home />} />
</Routes>
</Router>
</>
);
Because you are only returning one element inside that fragment, it is not really doing anything, so just remove the fragment or include another component inside of it.
React is not supposed to return adjacent elements, so if you just return one component or element there is no need for using <></>.
Remove <> </> as it might hinder your program for now
But in future for more than 1 components you might need to use these.

How to manipulate inside of a component in React?

We have a component <Book /> looks like following:
const Book = () => (<>
<Title />
<Thumbnail />
<Author />
</>)
And I want to give it a little change into this component, such looks like:
const CustomBook = () => (<>
<Title />
<h2>Hi, I am a subtitle</h2>
<Thumbnail>
<Author />
</>)
Let’s say new version of <Book /> is released:
const Book = () => (<>
<Title />
<Author /> {/* Position is changed *}
<Thumbnail /> {/* Position is changed *}
</>)
The position of <Author /> and <Thumbnail /> is now changed. But the <CustomBook /> doesn’t follow the structure of the new <Book /> since I wrote my own structure.
But what I actually wanted to do in the <CustomBook /> component was just appending an element after the <Title /> component.
Subsequently, one of my coworkers have suggested me the following approach:
<Book>
{builder => builder
// Assume that the keys are initially defined inside of the component
.appendAfter('title', <h2>Foobar</h2>)
.appendBefore(...)
.replace('foo', <Bar />)
.setProps('foo', { bar: 100 })
}
</Book>
But I don’t think it’s a good approach because:
1. The component is not self-descriptive.
2. The component is against React’s principals, that we should not manipulate the DOM directly. (Although it’s the virtual DOM)
I could define props such like afterTitle, but there are many components inside of the <Book /> component, therefore, it’s going to be hard to define all of the props. And we also should be able to remove or replace the elements.
I’m curious if there is a react-ish way to achieve this goal.
Thank you in advance.
(Edited)
TL;DR
Is there a way to append/replace/remove some component inside of a component, by an internally existing component, no matter how component internally changes, without defining props.
(Edited #2)
I'll publish the <Book /> component on NPM. So developers can't modify it. I want to allow developers to customize the component's internal DOM tree with such API as insertAfter('title', <Subtitle />). But not by props because I want to make it flexible.
If it is not necessary to have two separate components (one for <Book> and another <CustomBook>), then you can simply pass props to Book, for example, subtitle. Then in your Book component, you can check if it has a subtitle, and if so, display the subtitle. Ie,
const Book = () => (<>
<Title />
{ this.props.subtitle ? <h2>this.props.subtitle</h2> : null }
<Thumbnail />
<Author />
</>)
If you checked the reconciliation
1. Component instances are updated and reused based on their key.
2. React uses the key to match children in the original tree with children in the subsequent tree
Please provide key to each component and siblings elements
const CustomBook = () => (<>
<Title key={1}/>
<h2 key={2}>Hi, I am a subtitle</h2>
<Author key={3}/>
<Thumbnail key={4}/>
</>)
Note : for example purpose I have used 1,2,3.Please provide as per your requirements.

<div> cannot appear as a descendant of <p>

I'm seeing this. It's not a mystery what it is complaining about:
Warning: validateDOMnesting(...): <div> cannot appear as a descendant of <p>. See ... SomeComponent > p > ... > SomeOtherComponent > ReactTooltip > div.
I'm the author of SomeComponent and SomeOtherComponent. But the latter is using an external dependency (ReactTooltip from react-tooltip). It's probably not essential that this is an external dependency, but it lets me try the argument here that it is "some code that's out of my control".
How worried should I be about this warning, given that the nested component is working just fine (seemingly)? And how would I go about changing this anyway (provided I don't want to re-implement an external dependency)? Is there maybe a better design that I'm yet unaware of?
For completeness sake, here's the implementation of SomeOtherComponent. It just renders this.props.value, and when hovered: a tooltip that says "Some tooltip message":
class SomeOtherComponent extends React.Component {
constructor(props) {
super(props)
}
render() {
const {value, ...rest} = this.props;
return <span className="some-other-component">
<a href="#" data-tip="Some tooltip message" {...rest}>{value}</a>
<ReactTooltip />
</span>
}
}
Thank you.
If this error occurs while using Material UI <Typography> https://material-ui.com/api/typography/, then you can easily change the <p> to a <span> by changing the value of the component attribute of the <Typography> element :
<Typography component={'span'} variant={'body2'}>
According to the typography docs:
component : The component used for the root node. Either a string to use a DOM element or a component. By default, it maps the variant to a good default headline component.
So Typography is picking <p> as a sensible default, which you can change. May come with side effects ... worked for me.
Based on the warning message, the component ReactTooltip renders an HTML that might look like this:
<p>
<div>...</div>
</p>
According to this document, a <p></p> tag can only contain inline elements. That means putting a <div></div> tag inside it should be improper, since the div tag is a block element. Improper nesting might cause glitches like rendering extra tags, which can affect your javascript and css.
If you want to get rid of this warning, you might want to customize the ReactTooltip component, or wait for the creator to fix this warning.
If you're looking for where this is happening, in console you can use: document.querySelectorAll(" p * div ")
I got this warning by using Material UI components, then I test the component="div" as prop to the below code and everything became correct:
import Grid from '#material-ui/core/Grid';
import Typography from '#material-ui/core/Typography';
<Typography component="span">
<Grid component="span">
Lorem Ipsum
</Grid>
</Typography>
Actually, this warning happens because in the Material UI the default HTML tag of Grid component is div tag and the default Typography HTML tag is p tag, So now the warning happens,
Warning: validateDOMnesting(...): <div> cannot appear as a descendant of <p>
Details (and some HTML theory regarding the warning) : The <div> cannot appear as a descendant of <p> message is shown due to the fact that the permitted content of a <p> tag is according to the standards set to the Phrasing Context which does not include <div> tags. See the links for more details.
Your component might be rendered inside another component (such as a <Typography> ... </Typography>). Therefore, it will load your component inside a <p> .. </p> which is not allowed.
Fix:
Remove <Typography>...</Typography> because this is only used for plain text inside a <p>...</p> or any other text element such as headings.
This is a constraint of browsers. You should use div or article or something like that in the render method of App because that way you can put whatever you like inside it. Paragraph tags are limited to only containing a limited set of tags (mostly tags for formatting text. You cannot have a div inside a paragraph
<p><div></div></p>
is not valid HTML. Per the tag omission rules listed in the spec, the <p> tag is automatically closed by the <div> tag, which leaves the </p> tag without a matching <p>. The browser is well within its rights to attempt to correct it by adding an open <p> tag after the <div>:
<p></p><div></div><p></p>
You can't put a <div> inside a <p> and get consistent results from various browsers. Provide the browsers with valid HTML and they will behave better.
You can put <div> inside a <div> though so if you replace your <p> with <div class="p"> and style it appropriately, you can get what you want.
Details (and some HTML theory regarding the warning) : The <div> cannot appear as a descendant of <p> message is shown due to the fact that the permitted content of a <p> tag is according to the standards set to the Phrasing Context which does not include <div> tags. See the links for more details.
The warning appears only because the demo code has:
function TabPanel(props) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Box p={3}> // <==NOTE P TAG HERE
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
Changing it like this takes care of it:
function TabPanel(props) {
const {children, value, index, classes, ...other} = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Container>
<Box> // <== P TAG REMOVED
{children}
</Box>
</Container>
)}
</div>
);
}
I got this from using a react-boostrap <Card.Text> section of a component in React. None of my components were in p tags. <Card.Text> by default shows up as a in the HTML tree once rendered and basically having a custom React component returning its jsx elements within a <div> it causes a <p><div>...</div></p> which is a bad HTML. So to fix this issue if one is using <Card.Text> you can basically use the 'as' attribute as the following
<Card.Text as='div'> and this will resolve the warning because it allow a tree such as <div><div></div></div>
With Material UI !!!!!
I've spent an embarassing amount of time but thanks to this answer --> here by Alex C which gave this very simple yet smart solution
document.querySelectorAll(" p * div ")
So at my surprise , was the Material UI DialogContentText component DialogContentText API that caused the issue
So just use component={'span'} to fix the problem (it won't effect the style)
<DialogContentText id="alert-dialog-inputs" component={'span'}/>
I had a similar issue and wrapped the component in "div" instead of "p" and the error went away.
I got this from using a custom component inside a <Card.Text> section of a <Card> component in React. None of my components were in p tags
If you are using ReactTooltip, to make the warning disappear, you can now add a wrapper prop with a value of span, like this:
<ReactTooltip wrapper="span" />
Since the span is an inline element, it should no longer complain.
There is a problem in App.js during its rendering.
Don't use <div>...</div> to render just use <>...</>.
I had same issue with react-bootstrap and with Alex C's solution i found that i use <div> in <Card.Text> which is kinda <p>
<Card.Text>
<div>{name}</div>
<div>{address}</div>
<div>{size}</div>
</Card.Text>
I got this error when using Chakra UI in React when doing inline styling for some text. The correct way to do the inline styling was using the span element, as others also said for other styling frameworks. The correct code:
<Text as="span" fontWeight="bold">
Bold text
<Text display="inline" fontWeight="normal">normal inline text</Text>
</Text>
If you couldn't solve problem use bottom method
You have this problem because, you Open Grid tag or div in text tag and It can be false.
For example I write part of the code That have problem.look at it:
<Typography>
text
<Grid>
</Grid>
</Typography>
Be careful I open Grid tag in Typography tag. So It is false if we Open Grid tag in typography tag.
As far as my knowledge know when We open in typograghy tag, We are Deviating from the MUI standard.
So for best way you can us this Code:
<Grid>
<Typography>
text
</Typography>
</Grid>
If you used this code, you would not Any problem.
As result if you have problem again
You have to check components and
See in which component you did not Choose the correct mode.
You should check:
Span typography h1 h2 h3 h4 h5 h6 p
I hope I helped you .
I resolved that issue by removing my tag that I used to wrap around my 2 textfields that were causing that same error log.
You can not descendant of ;
Error: <p><div>aaaa</div></p>
Solution <div><p>aaaa</p></div>
(Extra)
Problem can be <p> elements inside <p> element in other similar errors.
Error:
<p>
<p>
</p>
</p>

Reactjs render component before other components

How can I specify that a component should be rendered absolutely before any other component?
I want to specify that <Footer /> and all the child components of footer should be rendered before any other components.
The reason I want this is because I have code that depends on the html that footer is rendering which means that the reference to <Footer /> is undefined in the other components if <Footer /> doesn't render first.
Here's an example:
export default class Layout extends React.Component {
...
render(){
return (
<Body />
<Footer /> //Render first
);
}
}
The only way I see for you do do that is:
Have the information about the render status for the footer in a state. (Let's assume your name it isFooterRendered and it is a boolean)
You set isFooterRendered to be false in the initial state.
You only render the children components when isFooterRendered is true
In componentDidMount you will have a reference to Footer, set isFooterRendered to be true.
(Some people claim that it's bad to setState on componentDidMount but in your case looks like a legit use case, aside from that React Docs expose a similar example)

Categories