ReactJS creating extra spans in HTML - javascript

I have started working on a project and inherited a large amount of ReactJS that I am trying to sort through and better understand. Currently there is a small issue I'm trying to fix in the app I'm working on.
Here is the code for the render:
render: function() {
return (
<div className="finish-content-container">
<div className='finish-instructions'>
<span>
{this.props.finishInfo.startpage.instructions || ""}
</span>
</div>
{
this.props.userData.score && !this.props.finishInfo.finishpage.hideScore ?
<div className="finish-results">
<span>{"Your Score: " + (this.props.userData.score || "")}</span>
</div> : ""
}
{
this.props.finishInfo.finishpage && this.props.finishInfo.finishpage.graph ?
<div className="finish-graph">
<div dangerouslySetInnerHTML={{__html: processStoredGraph(this.props.finishInfo.finishpage.graph, 250, 450)}}></div>
</div> : ""
}
{
this.props.userData.score && this.props.finishInfo.finishpage && this.props.finishInfo.finishpage.feedback ?
<div className='finish-results-feedback'>
{this._getConditionalText(this.props.finishInfo.finishpage.feedback, this.props.userData.score)}
</div> : ""
}
<div className="finish-content" dangerouslySetInnerHTML={{__html: this.props.finishInfo.startpage.content}}></div>
<div className="finish-button">
<span onClick={this.props.onClick} className="btn finish">REPLAY</span>
</div>
</div>
);
},
Here's what is happening: all the logic seems to work fine, but it's creating addition spans in the HTML and those spans are taking up real estate on the page, even when they have no data.
Any thoughts? I can include the HTML output from the page if that's helpful at all.

To answer your question: React inserts spans in the DOM for various reasons, including to wrap floating text nodes (see this answer), white space (see this answer), and (I think) to set placeholders for components that return null from the render method, among other things. If this is causing issues for you, it's probably because you're using CSS that operates on all span elements, or all span elements within the scope of your component. Ditch the CSS, or make it specific to the elements it needs to style, and you should be fine.
In my opinion, React's approach here is in keeping with the intent of the span element, which ought to be a layout no-op if not associated with a specific class.

Related

How can I specify the structure of a <div> conditionally in JSX?

I'm trying to create a responsive <div> inside a React return() statement, but every way I turn, my code is errored in VSCode. One example of my numerous efforts to structure this (and the one recommended by chatGPT) is:
<div>
{props.platform === "desktop" ? <div className="displaydiv"> : <div>}
</div>
</div>
In this case, the first <div> is errored by VSCode as having no closing tag.
I'm unsure whether or not this code would actually run, ie whether the problem might just be over-enthusiastic VSCode checking. But even if this is the problem, this is no help to me as these errors will obscure genuine errors in my project.
No, ternary on just the opening tag won't work. You can put it on the required attribute:
<div className={props.platform === "desktop" ? "displaydiv" : ""}>
</div>

react.js image onClick not working for some reason, while same function works for another div

i am making Faq questions in react and my question div displays text when clicked on whole body as shown below:
Here is my react code. div with class "question-body" works with onclick but when I click the Plus img it has no action,any mistakes?
export default function Question({data}){
let imagid = 'img'+data.id;
function toggle(){
document.getElementById(data.id).classList.toggle('question-p') ;
document.getElementById(imagid).classList.toggle('rotateimg');
}
return(
<div className="column width100 question">
<div onClick={() => toggle()} className="question-body">
<div className="flex-between">
<label className="faq-question">{data.question}</label>
<img onClick={() => toggle()} id={imagid} className='togglequestion' src={togglequestion}></img>
</div>
<p id={data.id} className='none' dangerouslySetInnerHTML={{ __html: data.answer }}></p>
</div>
</div>
)
}
even though the answer is pretty simple here, it would require you to redo most of your code.
In order to be working with React.js effectively, you need to learn the basics (component state management,... ) - https://reactjs.org/docs/getting-started.html
I highly encourage you not to use dangerouslySetInnerHTML as it can expose your code to easy exploits.
With React.js, you don’t really want to use Document Object Model APIs (via toggle function)

trying to add br tag between the text in react

I am trying to add br tag between the text in react.
can you guys tell me how to add it.
I tried adding br tag... but if I add I get tag in the browser.
providng my code below.
can you guys tell me how to fix it.
let sportsDescription = '';
if(sportsInfo !== '' && !isSportsSetupActive) {
sportsDescription = 'testing <br /> testing';
}else if(isSportsSetupActive) {
sportsDescription = 'testing <br /> testing';
}
return (
<div id="main" className="section flex-container flex-full">
<section className="page-content flex-item">
<section className="gray-box">
<h2>Welcome to your dashboard{formatName}.</h2>
<p className="ft-intro ft-day1 ft-day2">{sportsDescription}</p>
</section>
</section>
</div>
);
From the ReactJS Docs...
In general, setting HTML from code is risky because it's easy to inadvertently expose your users to a cross-site scripting (XSS) attack. So, you can set HTML directly from React, but you have to type out dangerouslySetInnerHTML and pass an object with a __html key, to remind yourself that it's dangerous.
In your example, {sportsDescription} is interpreted as a string. React won't see anything inside that variable as a DOM element. That's why your <br/> only renders as a string.
Alternatively, you could do this (but it's generally a bad idea)...
<p
className="ft-intro ft-day1 ft-day2"
dangerouslySetInnerHTML={{__html:sportsDescription}}
/>
This way, React correctly recognized your intent to include HTML inside the string sportsDescription and renders the desired <br/> element.
Here's a quote from an article that goes into greater detail about Getting Started with ReactJS:
The React module has a createClass method that takes an object as its only parameter. We define only one key to start with: render. The value of render is a function that returns a virtual DOM element. One of the keys to React’s performance is its virtual DOM abstraction. Essentially, it’s a difference engine that calculates the difference between the existing DOM and the DOM that is to be rendered and only modifies the necessary elements and attributes. Inside the render function, you may have noticed that I included HTML markup. That’s JSX. It won’t pass validation as legal Javascript. Instead, it requires the Babel transpiler.
JSX only looks like HTML. JSX is just a syntactic extension of Javascript, where every JSX "tag" is actually a call of React.createElement function. SO you can't treat JSX as HTML, and therefore you can't simply use strings with HTML inside and expect them to act like DOM. What you should do is return other valid JSX:
let sportsDescription = '';
if(sportsInfo !== '' && !isSportsSetupActive) {
sportsDescription = (
<span>testing<br />testing</span>
);
} else if(isSportsSetupActive) {
sportsDescription = (
<span>testing<br />testing</span>
);
}
return (
<div id="main" className="section flex-container flex-full">
<section className="page-content flex-item">
<section className="gray-box">
<h2>Welcome to your dashboard{formatName}.</h2>
<p className="ft-intro ft-day1 ft-day2">{sportsDescription}</p>
</section>
</section>
</div>
);
Here,
<span>testing<br />testing</span>
is actually four calls of React.createElement, the first one is for span element, and three other are for its children: text node, br, text node.
Please read the documentation carefully.

How to avoid extra wrapping <div> in React?

Today I have started learning ReactJS and after an hour faced with the problem..
I want to insert a component which has two rows inside a div on the page.A simplified example of what I am doing below.
I have an html:
<html>
..
<div id="component-placeholder"></div>
..
</html>
Render function like this:
...
render: function() {
return(
<div className="DeadSimpleComponent">
<div className="DeadSimpleComponent__time">10:23:12</div >
<div className="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
</div>
)
}
....
And below I am calling render:
ReactDOM.render(<DeadSimpleComponent/>, document.getElementById('component-placeholder'));
Generated HTML looks like this:
<html>
..
<div id="component-placeholder">
<div class="DeadSimpleComponent">
<div class="DeadSimpleComponent__time">10:23:12</div>
<div class="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
</div>
</div>
..
</html>
The problem that I am not a very happy that React forcing me to wrap all in a div "DeadSimpleComponent". What is the best and simple workaround for it, without explicit DOM manipulations?
UPDATE 7/28/2017: Maintainers of React added that possibility in React 16 Beta 1
Since React 16.2, you can do this:
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
This requirement was removed in React version (16.0), so now you are able to avoid that wrapper.
You can use React.Fragment to render a list of elements without creating a parent node, official example:
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
More here: Fragments
Update 2017-12-05:
React v16.2.0 now fully supports rendering of fragments with improved support for returning multiple children from a components render method without specifying keys in children:
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
If you are using a React version prior to v16.2.0, it is also possible to use <React.Fragment>...</React.Fragment> instead:
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
Original:
React v16.0 introduced returning an array of elements in render method without wrapping it in a div: https://reactjs.org/blog/2017/09/26/react-v16.0.html
render() {
// No need to wrap list items in an extra element!
return [
// Don't forget the keys :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
}
At the moment, a key is required for each element to avoid the key warning but this could be changed in future releases:
In the future, we’ll likely add a special fragment syntax to JSX that
doesn’t require keys.
You can use:
render(){
return (
<React.Fragment>
<div>Some data</div>
<div>Som other data</div>
</React.Fragment>
)
}
For further details refer to this documentation.
Use [], instead of ()'s to wrap the entire return.
render: function() {
return[
<div className="DeadSimpleComponent__time">10:23:12</div >
<div className="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
]
}
I created a component to wrap child components without a DIV. It's called a shadow wrapper: https://www.npmjs.com/package/react-shadow-wrapper
This is still required, BUT React now make sure to create elements without creating an additional DOM element.
The extra wrapping needed (normally with a parent div) because Reacts createElement method require a type parameter which is either a tag name string (such as 'div' or 'span'), a React component type (a class or a function). But this was before they introduce React Fragment.
Refer this NEW api doc for createElement
React.createElement : Create and return a new React element of the given type. The type argument can be either a tag name string (such as 'div' or 'span'), a React component type (a class or a function), or a React fragment type.
here is the official example, Refer React.Fragment.
render() {
return (
<React.Fragment>
Some text.
<h2>A heading</h2>
</React.Fragment>
);
}
I know this question has been answered, you can of course use React.Fragment which doesn't create a node but let's you group stuff like a div.
Additionally if you want to have fun you can implement (and learn lots of things) a React mode that removes the extra div's and for this I really want to share a great video on how you can do it on the react code base itself.
https://www.youtube.com/watch?v=aS41Y_eyNrU
This is of course not something that you would do in practice but it's a good learning opportunity.
You won't be able to get rid of that div element. React.render() needs to return one valid DOM node.
Here is one way to render "transculent" components:
import React from 'react'
const Show = (props) => {
if (props.if || false) {
return (<React.Fragment>{props.children}</React.Fragment>)
}
return '';
};
----
<Show if={yomama.so.biq}>
<img src="https://yomama.so.biq">
<h3>Yoamama</h3>
<Show>
There is workaround too. The below block code generates fragment without the need of React.Fragment.
return [1,2,3].map(i=>{
if(i===1) return <div key={i}>First item</div>
if(i===2) return <div key={i}>Second item</div>
return <div key={i}>Third item</div>
})

React navigation to control content in panel below

I'm new to React and looking for some best practices. I'm making a Chrome extension that's a small widget. The widget has 3 sections. Call Section A, Section B, and Section C. At the top of the widget I want to have buttons like so:
[logo] | Section A | Section B | Section C |
[
Panel Content (Default Section A)
]
And when one of those section links are clicked, the content in the panel below updates with the relevant content for that section.
My first thought was to render all of them, and then just hide jQuery show/hide() on the panels. It works, but I'd rather not do that because each panel loads some data asynchronously and I'd rather not pay that price up front if the user never clicks on the latter 2 links.
I've created React components for each section so their easy to swap out.
I then tried this:
showSectionB: function(){
React.renderComponent(
<SectionBList person={this.props.person} />,
document.querySelector('.main .panel')
);
},
render: function() {
return (
<div className="main">
<div className="actions">
<button className="T-I-ax7" onClick={this.showSectionB}>Section B</button>
</div>
<div className="panel">
<SectionAList person={this.props.person} />
</div>
</div>
);
}
It felt more logical, but feels weird I'm reaching inside a component for the container to place the component. On top of that, the whole browser locked up and gave me this message after the panel switched:
React attempted to use reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server.
Is there a better way to hand this?
The key to React is to always go through render() to render your application. User interaction should only fire events that trigger a re-render(). In your example onClick should call setState() to do that.
getInitialState: function () {
return {
section: "a"
};
},
showSectionB: function(){
// Update the component's state for a re-render().
this.setState({
section: "b"
});
},
render: function() {
if (this.state.section == "a") {
var section = <SectionAList person={ this.props.person } />;
}
else if (this.state.section == "b") {
var section = <SectionBList person={ this.props.person } />;
}
return (
<div className="main">
<div className="actions">
<button className="T-I-ax7" onClick={ this.showSectionB }>Section B</button>
</div>
<div className="panel">
{ section }
</div>
</div>
);
}
Updated thanks for the comment!

Categories

Resources