Can only set one of `children` or `props.dangerouslySetInnerHTML` - reactjs

I'm trying to set the inner HTML of an alert div, but receiving the error message : Can only set one of 'children' or props.dangerouslySetInnerHTML'.
Why does this happen ?
function alertContent(alert) { return {__html: alert.text} }
const Alerts = ({ alerts=[{level: 'warning', text:'<p>Warning message!</p>'}], onDismiss }) => (
<div className="alerts">
{alerts.map(alert =>
<Alert
bsStyle={alert.level}
key={alert.id}
onDismiss={onDismiss}
dangerouslySetInnerHTML={alertContent(alert)}
></Alert>
)}
</div>
)

I had this error message in a react application.
My issue was I had code as below
<p dangerouslySetInnerHTML={{ __html:stringContainingHtml}}> </p>
My issue was the space in the <p> </p> tags - since html gets injected inside these tags the space was causing an issue as it wasn't empty.
Hope this might help some people.

This happens because dangerouslySetInnerHTML can only be applied to one element. In your case, <Alert/> is a complex element made up of multiple children. That being said, the BS Alert component does accept HTML:
<Alert bsStyle="warning">
<strong>Holy guacamole!</strong> Best check yo self, you're not looking too good.
</Alert>
or
<Alert bsStyle="warning">
<span dangerouslySetInnerHTML={alertContent(alert)} />
</Alert>

Solution, You have to make a separate component to render element in which you are using dangerously set.....
For Example:
const RenderHTML = (props) => (<span dangerouslySetInnerHTML={{__html:props.HTML}}></span>)
YourData.map((d,i) => {
return <RenderHTML HTML={d.YOUR_HTML} />
})

you have to close the html tag short hand if there aren't inner HTML
<Alert dang...={} />
instead <Alert></Alert>

I have solved this issue myself.
When you are recursively rendering a component, you must separate out the part of the component where dangerouslySetInnerHTML is being used into another component and then use that component in the one you are recursively rendering.

Related

how to resolve "Prop `id` did not match. Server: "react-tabs-30" Client: "react-tabs-0" console issue?

i am trying tab in next in next.js, but every time i use it it show a console warning link this Prop `id` did not match. Server: "react-tabs-30" Client: "react-tabs-0", i know it isn't effect my app but it is so annoying. how to solve this waring
<Tabs>
<div className="tab-controler ml-sm-auto">
<TabList className="tab-lists list-inline d-flex flex-wrap nav mb-3" style={{ background: '#F8F8F8' }}>
<Tab className={`${CostCalculatorStyle.PEItem} tab-lists__item`}>Buy & Ship for me</Tab>
<Tab className={`${CostCalculatorStyle.PEItem} tab-lists__item`}>Ship for me</Tab>
</TabList>
</div>
<TabPanel key={"tabpanel_ship"}>
<div className="row">
<div className="col-lg-6">
<ShipForMeForm handleFormValue={handleFormValue} handleProductValue={handleProducts} handleRef={handleRef} />
</div>
<div className="col-lg-6 align-self-center">
<div className="costcalc-empty-thumb text-center">
<Image
src="/assets/topNavbarPages/costCalculator.svg"
alt="Cost Calculator"
width="469"
height="288"
/>
</div>
</div>
</div>
</TabPanel>
<TabPanel key={"tabpanel_buy_ship"}>
<div className="row">
<div className="col-lg-6">
<ShipForMeForm handleFormValue={handleFormValue} handleProductValue={handleProducts} handleRef={handleRef} />
</div>
<div className="col-lg-6 align-self-center">
<div className="costcalc-empty-thumb text-center">
<Image
src="/assets/topNavbarPages/costCalculator.svg"
alt="Cost Calculator"
width="469"
height="288"
/>
</div>
</div>
</div>
</TabPanel>
</Tabs>
as you can see i use react-tabs for tab but i also work on react js where i use the same code but it didn't show this console warning. so my question is why it is happing? and how i can solve it ?
In next js i fixed it like that
import dynamic from 'next/dynamic'
const Tabs = dynamic(import('react-tabs').then(mod => mod.Tabs), { ssr: false }) // disable ssr
import { Tab, TabList, TabPanel } from 'react-tabs'
it work for me
The best solution I know of is just to set the id yourself in the <Tabs> component. Ex: <Tabs id={1}>
See https://github.com/chakra-ui/chakra-ui/issues/4328#issuecomment-890525420 for more details and examples.
NextJs generating code in server side as you know.
This error means that something on the server is different from the Client. This can happen if the client does a re-render.
For example.
export default function Test(props) {
return (
<>
<span>{props.name}</span>
</>
);
}
I have this simple Test component.And I send name (1) prop from another component to this Test component. And if I change this name (to 2) in client using redux (for example I have another name in my redux store) after page generated I get this error.
props did not match server "1" client "2"
To solve this error I need to just not change this name with redux after page generated in server. The data can be change only with user manipulations after page rendered in server.
Same thing happened to me when I use Tabs from react-bootstrap. Koushik Saha's answer can be apply for that also but with a small change. Need to put react-bootstrap instead react-tabs
const Tabs = dynamic(import('react-bootstrap').then(mod => mod.Tabs), { ssr: false })
In case you miss it
If you are using Nextjs + Material-ui, there are actually custom codes that you can/need to include in your _document.js and _app.js to remove the server-side injected CSS so the CSS is recreated when page loads.
As codes changes with mui's and nextjs' version, i will refer you to the repository directly
https://github.com/mui-org/material-ui/tree/master/examples/nextjs/pages
As per the documentation in the react-tabs repo/npmjs.org page (https://www.npmjs.com/package/react-tabs):
import { resetIdCounter } from 'react-tabs';
resetIdCounter();
ReactDOMServer.renderToString(...);
I was having the same issue and called the resetIdCounter function inside my parent component to the tabs structure and cleared up the error.
Not sure if maybe there is a better place to use this function, like maybe in a useEffect hook or something, but I'm going with this for now.

Newbie to React : Any help would be greatly appreciated

I am doing a code challenge and am very new to React. I am used to hard coding things, and I need to loop in data from a JS file. I am familiar with HTML and CSS so styling will be no problem, but how I can pull in the data from the menu items without hardcoding. Below are links to what I have in the project files as well as a reference as to what it should look like. Thanks!
[1]: https://i.stack.imgur.com/JtE4X.png
[2]: https://i.stack.imgur.com/n412K.png
[3]: https://i.stack.imgur.com/ZVSl2.png
Here's a simplified example
Interactive sandbox
https://codesandbox.io/s/lucid-lovelace-kr6rr?fontsize=14&hidenavigation=1&theme=dark
Here's the code:
function myComponent() {
// Here's your data
// You'll probably want to set this to state after fetching it
// (It doesn't need to be in a const)
const myList = [
"https://i.stack.imgur.com/JtE4X.png",
"https://i.stack.imgur.com/n412K.png",
"https://i.stack.imgur.com/ZVSl2.png"
];
// map over your data
// here we are rendering an html img for each item
// and we give each a key to help react keep a record of what is has rendered
return (
<div>
{myList.map(url => <img src={url} key={url} />)}
</div>
)
}
Hope it helps!
On line 19, try
let menuItems = this.state.menuItems.map((item) => {
<MenuItem name={item.name} img={item.imageName} price={item.details.price} />
}
Then in your return,
<div id="combo-header">
<h1>Combo Meals</h1>
{menuItems}
</div>
You can also choose to loop within your render instead of assigning to its own menuItem variable.
<div id="combo-header">
<h1>Combo Meals</h1>
{this.state.menuItems.map((item) => {
<MenuItem name={item.name} img={item.imageName} price={item.details.price} />
}}
</div>
Note that the second option requires the javascript to be wrapped in {} so that you can write javascript directly in the JSX.
After this, you'd write a MenuItem component that would intake the props above.
You will also have to perform a check that the array is not empty before mapping over it, or there will be errors.

SSR with Helmet also render async meta and content?

I'm trying to build an app where needs to get data before send props to <Helmet> but I don't know if it's possible because I don't see nothing like it in the docs.
And there's no possible to show this content in Helmet component. The content is always empty
The Helmet component is the HtmlPage component.
In the code below, we receive an SEO undefined error.
https://github.com/nfl/react-helmet/issues/409
<HtmlPage
{...this.props.client.info.SEO}
>
<ThemeProvider theme={this.state.theme}>
<div className='wrapper' id='wrapper'>
{loading && <Loading
client={this.state.client}
/>}
<div className="content" id='page-wrapper'>
<h1>Its ok for now ====</h1>
<p>
{JSON.stringify(this.props.client)}
</p>
<div>
{!!this.props.client.info &&
<p>{JSON.stringify(this.props.client.info.SEO)}</p>}
</div>
</div>
</div>
</ThemeProvider>
</HtmlPage>
The react-helmet-async don't work.
https://github.com/staylor/react-helmet-async
You need to implement a second renderPass to allow it to collect header elements. I tried react-tree-walker for this, but it didn't work. In the end I added a second renderPass using renderToStaticMarkup. E.g.
`
const stream = renderToNodeStream(<App preloadedState={preloadedState} />);
// extra render pass
renderPass(<App preloadedState={preloadedState} />);
`

onClick on div element won't pass target id

I have an issue in my React.js app with the target id not being passed if a onClick event is attached on a div element.
This is how I add the component:
<MenuOption title="Users" onOptionClick={this.onOptionClick}/>
This is the jsx-part of my MenuOption component:
<div id={title} className="row menu-option" onClick={onOptionClick}>
<p>{title}</p>
</div>
As you can see I'm simply assigning the prop title as the id and the onClick event.
Back in the parent component, implementation of the onClick method:
onSidebarOptionClick(e) {
console.log(e.target.id);
}
This does not seem to work since it always logs undefined.
However, if I add the id and the onClick event to my p element instead...
<div className="row menu-option">
<p id={title} onClick={onOptionClick}>{title}</p>
</div>
...it works just as expected, the correct id logs at every click.
So why is not the id passed if the click event is attached to a div?
I`m using ES6 and babel.
I should clarify that I'm using "dumb" components, declaring them like this:
const MenuOption = ({title, onOptionClick})
...which is why don't need to use {this.props.title} when using it.
Not sure as your Question missing constructor but try one of the following--
Method 1 (JSX):
<MenuOption title="Users" onOptionClick={this.onOptionClick.bind(this)}/>
Method 2 (es6):
constructor(props) {
super(props);
this.onOptionClick = this.onOptionClick.bind(this);
}
Method 3(es-next):
onSidebarOptionClick = (e) => {
console.log(e.target.id);
}
As you're passing onOptionClick as a prop to <MenuOption/>, it should be declared as this.porops.onOptionClick.
<MenuOption/> should look like this
<div id={title} className="row menu-option" onClick={thi.props.onOptionClick}>
<p>{title}</p>
</div>
Hope this helps!

React: Invariant Violation (without table)

I have looked some answer in stackoveflow. But most of them have something todo with <table> and <tbody>. But my problem is nothing to do with that.
I render this <GISMapDropdownMenu> component using ScriptjsLoader of react-google-maps library.
initialCustomSetup: function() {
let GISMapDropdownMenu = this.refs.cornermenu;
if (googleMapInstance.props.map.controls[google.maps.ControlPosition.TOP_LEFT].j.length === 0) {// push only once
googleMapInstance.props.map.controls[google.maps.ControlPosition.TOP_LEFT].push(GISMapDropdownMenu);
GISMapDropdownMenu.style.zIndex = 1;
GISMapDropdownMenu.style.display = 'inline-block';
}
},
render: function() {
return(
<ScriptjsLoader
**** some setup ****
googleMapElement={
<GoogleMap
ref={googleMap => {
if (googleMap) {
googleMapInstance = googleMap;
layerType = self.props.layerType;
self.initialCustomSetup();
}
return;
}} >
<GISMapDropdownMenu
ref="cornermenu"
availableDesa={self.props.availableDesa}
availableDesaColor={self.props.availableDesaColor} />
{self.props.children}
</GoogleMap>
}
/>);
Here is the implementation of GISMapDropdownMenu.
<div className="gmnoprint GISMap-dropdownmenu" style={{display: 'none'}}>
<div>
<div ref="icon" className="GISMap-dropdownmenu--icon" onClick={this.handleIconClick}>
<img src={BurgerIcon} draggable="false" />
</div>
<div ref="content" className="GISMap-dropdownmenu--content" style={{display: 'none'}}>
<div className="GISMap-dropdownmenu--content_header">
<div className="GISMap-dropdownmenu--content_header__title">List of Desa ({number_of_desa})</div>
<div className="GISMap-dropdownmenu--content_header__cross" onClick={this.handleCrossCLick}>
<img src={CrossIcon} draggable="false" />
</div>
</div>
<div className='GISMap-dropdownmenu--content_list'>
{array_div_element_inrange_assigned_desa}
{array_div_element_inrange_desa}
{array_div_element_assigned_desa}
</div>
</div>
</div>
</div>
{array_div_element_something} is array of this.
<div key={"desa_name-"+desa.desa_name} className={"GISMap-dropdownmenu--content_list__"+desa_color.status}>Desa {desa.desa_name}</div>;
I got this error when use <GISMapDropdownMenu /> component.
Uncaught Error: Invariant Violation: processUpdates(): Unable to find child 97 of element. This probably means the DOM was unexpectedly mutated (e.g., by the browser),
I realised something:
I move the DOM of <GISMapDropdownMenu /> component after mounted. Because I need it to be in the top left of google map.
Any suggestion?
Potential problems: First off, these are guesses as I don't do React all the time, but having said that, here are some possible causes of this:
1) Unmounting components:
This probably means that setState is being called in a callback that was firing after the component that initially started the request has already been unmounted from the dom.
More details on this type of error
2) Having incomplete HTML tags in your markup
For example, adding a <p> tag without the closing </p>. The browser likes all html tags to be complete, so if it doesn't see an end tag for something, it'll add it. Try getting the HTML of your resulting component and comparing it to what you expect. Also remove the child components bit by bit (e.g. remove ) to see when it starts to work so you know what causes this problem. Your html from what I can see doesn't cause this.
3) Build your child components before rendering
Maybe you need to do as this similar answer does
4) Changing the DOM using something other than React
Is your page using jquery or something to change this component in anyway? ie bind events or add/remove anything? If so, this can be causing that as well. Try disabling this and see if it solves the problem
If none of the above help, I'd suggest adding a JSFiddle so people can see what the problem is for sure.

Resources