Unknown props warning when passing props to children - reactjs

I'm trying to create a reusable dropdown menu wrapper component using this pattern:
class DropdownMenu extends React.Component {
render() {
return (
<span>
{React.cloneElement(
this.props.children,
{
menuOpen: this.props.menuOpen,
toggleMenu: this.props.toggleMenu
}
)}
</span>
);
}
}
const HeaderUserDropdown = ({menuOpen, toggleMenu }) => (
<DropdownMenu>
<div className={menuOpen ? 'visible' : ''}>
<button onClick={toggleMenu} />
</div>
</DropdownMenu>
)
But I get an error along the lines of Warning: Unknown props menuOpen, toggleMenu on <div> tag. Remove these props from the element. I know that I can use data- to get this working correctly, but that seems sort of hacky. What's the correct way to pass these props down to the children?

React distinguishes between HTML elements which are written in lower case (e.g. <div>) and React components which start with a capital letter.
In your code, you're trying to clone an HTML div element and add the properties menuOpen and toggleMenu, but these attributes are not supported by <div>, hence the warning. You need to set custom attributes on an HTML element, you'll need to use the data- prefix convention.

Related

Can not get in order TS with forwardRef in React App

I have component which so far was used as functional one like this (thunk is "any" temporarily for simplicity)
interface Props {
thunkFetchMovies: any;
}
const SearchInput = (props:Props) => {
const { thunkFetchMovies } = props;
return (
<div className="TopBar__center">
<div className="search">
</div>
</div>)
}
Due to need of modifying DIV with className 'search' I try to rewrite the component with forwardRef. Have already checked few suggestions from websites, but nothing works as expected.
Tried to follow these sources:
https://fettblog.eu/typescript-react-generic-forward-refs/
https://www.carlrippon.com/react-forwardref-typescript/
as well as few similar questions here, but it does not work as expected. How should I type it?
If you need to modify the css you don't need the ref of the element in the Dom.
You can edit the class name based on props, for example:
<button className={props.foo == "bar" ? "search":""} />

Dynamically changing React component tag

I'm creating a Landing page for a project and want to reduce my code by making a helper function to display my four different paper components. Everything seems to be working correctly except for displaying my Icon components that are within the papers.
When I console log Icon it is the correct text, yet the component doesn't appear on the page and I receive these two warnings for each component tag:
"Warning: The tag <CardTravelIcon> is unrecognized in this browser. If you
meant to render a React component, start its name with an uppercase letter."
and
"Warning: <CardTravelIcon /> is using uppercase HTML. Always use lowercase
HTML tags in React."
If I just hard code in CardTravelIcon or any of the other 3 component names in that exact format instead of using Icon from my map function, everything works as expected. Below is the code for my helper function:
class Landing extends Component {
renderPapers() {
const classes = this.props.classes;
return _.map(infoPapers, ({ description, Icon }) => {
return (
<Grid item xs={6} sm={3} key={Icon}>
<Paper className={classes.paper}>
<Icon className={classes.paperIcons} />
{description}
</Paper>
</Grid>
);
});
}
I'm at a loss and would appreciate any help. Thank you.
So you want to pass a component as a variable, right?
Let's say you have this minimal CardTravelIcon component:
const CardTravelIcon = ( props ) => (
<div className={ props.className }>Card Travel Icon</div>
);
And infoPapers data like this (Icon is a reference to the component):
const infoPapers = [
{
description: "Paper 1 description",
Icon : CardTravelIcon
}];
You didn't show us the infoPapers data, but I suspect you're trying to pass a string as the component, e.g. { Icon : "<CardTravelIcon />" } and expect it to work like setting innerHTML (rendering HTML from a string). This is not the case in React, the JSX code needs to be transpiled into calls to React.CreateElement first, and it isn't done by parsing strings.
If you pass references to components everything should be rendered just fine with the following render method (note: removed lodash in favor of native map method, for clarity):
class Landing extends React.Component {
render() {
return infoPapers.map(({ description, Icon }, idx) => {
return (
<div key={ idx }>
<Icon />
{description}
</div>
);
});
}
};
Here's a working example: https://jsfiddle.net/svygw338/

REACT Warning Unknown props parsing to child component [duplicate]

I've built my own custom react-bootstrap Popover component:
export default class MyPopover extends Component {
// ...
render() {
return (
<Popover {...this.props} >
// ....
</Popover>
);
}
}
The component is rendered like so:
// ... my different class ...
render() {
const popoverExample = (
<MyPopover id="my-first-popover" title="My Title">
my text
</MyPopover >
);
return (
<OverlayTrigger trigger="click" placement="top" overlay={popoverExample}>
<Button>Click Me</Button>
</OverlayTrigger>
);
}
Now, I want to add custom props to MyPopover component like that:
my text
And to use the new props to set some things in the popover
for example -
<Popover {...this.props} className={this.getClassName()}>
{this.showTheRightText(this.props)}
</Popover>
but then I get this warning in the browser:
Warning: Unknown props popoverType on tag. Remove these props from the element.
Now, I guess that I can just remove the {...this.props} part and insert all the original props one by one without the custom props, but In this way I lose the "fade" effect and also it's an ugly way to handle this problem. Is there an easier way to do it?
Updated answer (React v16 and older):
As of React v16, you can pass custom DOM attributes to a React Component. The problem/warning generated is no longer relevant. More info.
Original answer (React v15):
The easiest solution here is to simply remove the extra prop before sending it to the Popover component, and there's a convenient solution for doing that.
export default class MyPopover extends Component {
// ...
render() {
let newProps = Object.assign({}, this.props); //shallow copy the props
delete newProps.popoverType; //remove the "illegal" prop from our copy.
return (
<Popover {...newProps} >
// ....
</Popover>
);
}
}
Obviously you can (and probably should) create that variable outside your render() function as well.
Basically you can send any props you want to your own component, but you'd have to "clean" it before passing it through. All react-bootstrap components are cleansed from "illegal" props before being passed as attributes to the DOM, however it doesn't handle any custom props that you may have provided, hence why you have to do your own bit of housekeeping.
React started throwing this warning as of version 15.2.0. Here's what the documentation says about this:
The unknown-prop warning will fire if you attempt to render a DOM element with a prop that is not recognized by React as a legal DOM attribute/property. You should ensure that your DOM elements do not have spurious props floating around.
[...]
To fix this, composite components should "consume" any prop that is intended for the composite component and not intended for the child component.
For further reading, check this page from the official react site.

Add custom props to a custom component

I've built my own custom react-bootstrap Popover component:
export default class MyPopover extends Component {
// ...
render() {
return (
<Popover {...this.props} >
// ....
</Popover>
);
}
}
The component is rendered like so:
// ... my different class ...
render() {
const popoverExample = (
<MyPopover id="my-first-popover" title="My Title">
my text
</MyPopover >
);
return (
<OverlayTrigger trigger="click" placement="top" overlay={popoverExample}>
<Button>Click Me</Button>
</OverlayTrigger>
);
}
Now, I want to add custom props to MyPopover component like that:
my text
And to use the new props to set some things in the popover
for example -
<Popover {...this.props} className={this.getClassName()}>
{this.showTheRightText(this.props)}
</Popover>
but then I get this warning in the browser:
Warning: Unknown props popoverType on tag. Remove these props from the element.
Now, I guess that I can just remove the {...this.props} part and insert all the original props one by one without the custom props, but In this way I lose the "fade" effect and also it's an ugly way to handle this problem. Is there an easier way to do it?
Updated answer (React v16 and older):
As of React v16, you can pass custom DOM attributes to a React Component. The problem/warning generated is no longer relevant. More info.
Original answer (React v15):
The easiest solution here is to simply remove the extra prop before sending it to the Popover component, and there's a convenient solution for doing that.
export default class MyPopover extends Component {
// ...
render() {
let newProps = Object.assign({}, this.props); //shallow copy the props
delete newProps.popoverType; //remove the "illegal" prop from our copy.
return (
<Popover {...newProps} >
// ....
</Popover>
);
}
}
Obviously you can (and probably should) create that variable outside your render() function as well.
Basically you can send any props you want to your own component, but you'd have to "clean" it before passing it through. All react-bootstrap components are cleansed from "illegal" props before being passed as attributes to the DOM, however it doesn't handle any custom props that you may have provided, hence why you have to do your own bit of housekeeping.
React started throwing this warning as of version 15.2.0. Here's what the documentation says about this:
The unknown-prop warning will fire if you attempt to render a DOM element with a prop that is not recognized by React as a legal DOM attribute/property. You should ensure that your DOM elements do not have spurious props floating around.
[...]
To fix this, composite components should "consume" any prop that is intended for the composite component and not intended for the child component.
For further reading, check this page from the official react site.

How does the ReactBootstrap OverlayTrigger container property work?

I have a popover inside OverlayTrigger.
I define it as
const myOverlayTrigger = <ReactBootstrap.OverlayTrigger
placement='bottom' overlay={<ReactBootstrap.Tooltip>...</ReactBootstrap.Tooltip>}>
{myContent}
</ReactBootstrap.OverlayTrigger>;
Then I render it inside one of my elements like that:
<li>{myOverlayTrigger}</li>
I want to render OverlayTrigger itself inside <li> but it renders inside body, as defined in documentation. I'm trying to use container attribute to render it inside parent <li>.
First, I tried to assign ID to <li> and pass this ID as a string to container=... (which isn't a best way).
Second, I tried to create additional element <span></span> and render it inside along with {myOverlayTrigger}. Also I pass it (assigned to variable) to container attribute
const c = <span></span>;
... container={c} ...
<li>{c} {myOverlayTrigger}</li>
Both approaches consistently gives an error not a dom element or react component.
Obviously assigning <li>...</li> itself as a container doesn't work either as it being defined after myOverlayTrigger is defined.
Question: how to use it right?
ReactBootstrap.Overlay is recommended for the reason listed in the document.
The OverlayTrigger component is great for most use cases, but as a
higher level abstraction it can lack the flexibility needed to build
more nuanced or custom behaviors into your Overlay components. For
these cases it can be helpful to forgo the trigger and use the Overlay
component directly.
For your case, the code below renders the ReactBootstrap.Overlay component into a list item with React ref attribute.
getInitialState() {
return (
show: false
);
},
render() {
return (
<ul>
<li ref="dest" onClick={ () => {
this.setState( { show: !this.state.show } );
}}>my contents</li>
<ReactBootstrap.Overlay placement="bottom"
show={ this.state.show } container={ this.refs.dest }>
<ReactBootstrap.Tooltip>tooltip</ReactBootstrap.Tooltip>
</ReactBootstrap.Overlay>
</ul>
);
}
When the tooltip is displayed by clicking, the resulting HTML would be
<ul data-reactid=".0.1.0.0.0.0.0.1.1.1.1:$3.1.1">
<li data-reactid=".0.1.0.0.0.0.0.1.1.1.1:$3.1.1.0">
contents
<div>
<div role="tooltip" class="fade in tooltip right" data-reactid=".3">
<div class="tooltip-arrow" data-reactid=".3.0"></div>
<div class="tooltip-inner" data-reactid=".3.1">My tooltip</div>
</div>
</div>
</li>
<span data-reactid=".0.1.0.0.0.0.0.1.1.1.1:$3.1.1.1">,</span>
<noscript data-reactid=".0.1.0.0.0.0.0.1.1.1.1:$3.1.1.2"></noscript>
</ul>

Resources