There are any ways of suppressing single validateDOMNesting warning in React? - reactjs

In my case I have something like this:
<div className="projects">
{getProjectList().map(p => (
<Link key={p.id}
className='project'
to={`/project/${p.id}`}
style={{border: '2px solid red'}}
>
#{p.id} - {p.name}
<div className="helpers">
<Button
icon="trash"
size="mini"
color="red"
onClick={e => {
e.preventDefault();
e.stopPropagation();
setDeleting(p);
}}
/>
<Button
size="mini"
color="red"
as={Link}
to={`/edit/${p.id}`}
>Edit</Button>
</div>
</Link>
))}
</div>
which visually is represented like this:
And I would prefer to keep it like this because it works as it is intended.
Additional explanation why I want it this way: I want to provide to user ability to click on both links with right mouse button and choose "Open Link in New Tab". To navigate to details of the projects and also navigate to edit form to change properties of the project (These are two different pages).
But in this case I have two times tag embedded in each other and React generate:
Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>.
any ways to suppress it?

I'm working on rendering emails with React and ran into the same issue because it's recommended to exclude <tbody> for some Email Service Providers (link)
I wasn't able to suppress the error directly, instead, I added a __isTest prop to my component and then only added <tbody> when __isTest === true:
return __isTest ? (
<table>
<tbody>
<tr>
<td>{children}</td>
</tr>
</tbody>
</table>
) : (
<table>
<tr>
<td>{children}</td>
</tr>
</table>
)
I would definitely prefer to be able to suppress the warning, but this is an alternative that may work in certain cases.

Just add /* eslint-disable */ in the file you want the warnings to be suppressed as explained in the official github repository how to hide unwanted warning.
Remember that's not best practice.

Related

React Testing Library toBeInTheDocument failing despite being in the DOM

I have a test which basically contains the following code:
const row = await screen.findByText('Test Subject');
try {
expect(row).toBeInTheDocument();
} catch (e) {
screen.debug();
throw e;
}
The debug is for trying to track this down. findByText succeeds, and does find the element. I can log this out, and it appears. But when I do the expect, it fails SOMETIMES. It's unpredictable. I'm pretty certain the DOM isn't changing between calls, as I have logs out on every render and nothing logs out between the find and the assert.
I won't print the whole DOM tree, but on the catch debug, I can clearly see the row.
<tr
class="sc-jgrIVw bDPrDC"
>
<td
class="sc-jeqYYF hinrdE"
>
<div
class="sc-clIAKW jvtlES"
>
05-Dec-2022 12:08
</div>
</td>
<td
class="sc-jeqYYF ijUrhn"
>
<div
class="sc-clIAKW jvtlES"
>
<div
title="Test"
>
Test
</div>
</div>
</td>
<td
class="sc-jeqYYF ijUrhn"
>
<div
class="sc-clIAKW jvtlES"
>
Test Subject
</div>
</td>
</tr>
So as far as I can tell, RTL knows my DOM is there, the DOM log shows its there, but toBeInTheDocument throws. What could I be missing?

Getting an object from a table row in React

I'm a beginner working on a simple CRUD, and all I want to do is get the user from the selected row. If you look below:
{/* ANCHOR - TABLE ROWS */}
{admins.map((user, index) => (
<tbody key={index}>
<tr>
<td style={{fontWeight: 'bold'}}>{user._id}</td>
<td>{shortenStr(user.username)}</td>
<td>{shortenStr(user.firstName)}</td>
<td>{shortenStr(user.lastName)}</td>
<td>{shortenStr(user.dob)}</td>
<td>
<div className="button-div">
<button id="updateUser"
className="button-update-admin"
onClick={handleClick && console.log(user.firstName)}>
</button>
</div>
</td>
</tr>
</tbody>
))}
Console.log gives me the first names of every user in the table, such as:
John
Steve
Frank
Ideally I would like to pass the user Data into my handle click function so that I can create a context, perhaps. Any help is appreciated, thanks!
Please change -
onClick={handleClick && console.log(user.firstName)}>
To
onClick={() => {
console.log(user.firstName)
}}
Or if you want to have a separate onClick function with the event data -
function handleClick(event, user) {
console.log(user.firstName);
}
...
onClick={(event) => handleClick(event, user)}

Links to external resource are empty in React

In a React app I have a Table tbody of which looks the following way:
<tbody>
{
this.state.datasets.map((datasetName, idx) => {
return (<tr>
<td>
<div className={"pretty p-default p-curve"}>
<input id = {"datasetCheckBox" + idx}
checked = {this.state.checkBoxSelected === datasetName}
type="radio" name="datasetName"
onChange={(e) => this.checkBoxSelected(datasetName, e)}/>
<div className={"state p-primary"}>
<label>{idx}</label>
</div>
</div>
</td>
<td>{datasetName}</td>
<td>{datasetsJSON["datasets"][datasetName]["region"]}</td>
<td>{datasetsJSON["datasets"][datasetName]["authors"]}</td>
<td>
<a href={datasetsJSON["datasets"][datasetName]["link"]}>{datasetName}</a>
</td>
</tr>)
}, this)
}
</tbody>
The link is shown with an empty href even though other parameters of the table from datasetsJSON["datasets"][datasetName] are set correctly. I tried using React Router and the only piece of code that redirected to links is in the answer here:
React-Router External link
But in the answer to the question above if I set path="/", when the table loads, it is just redirecting me straight away to the first link. I would expect then that for each link the path should be different, but supplying datasetsJSON["datasets"][datasetName]["link"] as a path does not work either. Why is the simple link a empty? How could I fix it?
I solved it by using onClick method instead of href link attribute. In the table I have:
<td onClick = {() => this.articleClicked(datasetName)}>
<span role="button"><a>{datasetName}</a></span>
</td>
Then, onClick method:
articleClicked = (datasetName) => {
let url = datasetsJSON["datasets"][datasetName]["link"];
window.open(url);
}
<span role="button"> is needed for the cursor to show hand when the user is hovering over the link. It is bootstrap thing.

How to pass VideoId from a list to React Modal Video

I am trying to play youtube video in a modal window on button click in my react app. I am using "react-modal-window" node module for the modal. I am getting an array of youtube video Ids and passing the ids to modal in the following way but only the last id from the array is taken by the modal window. However if I try to print the video id, am getting respective ids. Can any one please help in fixing this?
<tr>
<th></th>
{filteredProductVideoId.map(k =>
<td key={k}>VideoID: {k}
<ModalVideo channel='youtube' isOpen={this.state.isOpen} videoId={k}
onClose={() => this.setState({isOpen: false})} />
<button onClick={this.openModal}>Watch Video</button>
</td>)
}
</tr>
To view the output, please click this link -https://7jrz33j35x.codesandbox.io/ Select all four products and click compare button. A tabular view of comparison displays. In the last row there is a "watch video" button for each product. Beside the button, respective id got displayed(for debugging purpose) but on clicking watch video, the video with last id from the array is played
pass the clicked button video id via state.. like below
this.state = {
//use this props inside modal video view
currentVideoId : null
}
this.updateVideoId(currentVideoId){
this.setState({currentVideoId})
}
//your jsx change button onClick like below
<tr>
<th></th>
{filteredProductVideoId.map(k =>
<td key={k}>VideoID: {k}
<ModalVideo channel='youtube' isOpen={this.state.isOpen} videoId={k}
onClose={() => this.setState({isOpen: false})} />
<button onClick={()=>{this.updateVideoId(k)}}>Watch Video</button>
</td>)
}
</tr>

react use Link on entire tr failed

<tbody>
{map(items, item =>
<Link to={routeUrl(ROUTES.SOMEWHERE, item.id)}>
<tr key={item.id}>
<td>
{item.name}
</td>
<td>
{item.country}
</td>
</tr>
</Link>
)}
</tbody>
This won't work, any clue why? I can put the Link component within the td but I want the entire row to be clickable.
According to JSX rules, a Link component should contain only a string and not another component. Instead of using Link you can add onClick method on tr component and then you can define the route where you want to go in the body of onClick.

Resources