Class based component has ref warning of functional component - reactjs

I have a class based component by itself that is warning
Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
In addition I am not able to reference the ref
Here is a code sandbox. https://codesandbox.io/s/inspiring-currying-023wf?file=/src/App.js

Turns out Row within reactstrap must be a functional components.
Therefore instead of
<Row ref={this.myRef}>
...
</Row>
I had to use
<div ref={this.myRef}>
<Row>
...
</Row>
</div>

The Row component within react strap is a functional component and therefore is not an instance so it cannot have the ref= attribute.
Check out the documentation here. https://reactjs.org/docs/refs-and-the-dom.html#refs-and-function-components. And this link as well https://reactjs.org/docs/forwarding-refs.html if you want to use refs on that particular component.
You could also choose to override the component with a custom class component if you want to expand the usage.

Related

How can I set the Overlay container property when using OverlayTrigger?

I'm using the OverlayTrigger component to get hover behavior for tooltips, and therefore not using the Overlay component directly. The Overlay component has a container property that I'd like to use to remedy the tooltip getting cut off by its natural container element.
I've attempted to pass a popperConfig object, but that's not working. I've also tried adding a container attribute to the OverlayTrigger component.
<Container fluid className='flex-fill' ref={rowContainer}>
...
<OverlayTrigger delay={{show: 500}} overlay={renderUserTooltip}
popperConfig={{container: rowContainer}}>
<FaUser/>
</OverlayTrigger>
How can I set the container for the Overlay when the Overlay component isn't directly used?
React bootstrap doesn't have a container prop or something similar (I mean it has a target prop but as this part of the docs suggests, for the OverlayTrigger the type is null, so it doesn't accept values and I don't think you can trick it to accept (and I don't think it would be wise to try).
But a pretty nice example, that shows some sort of a workaround in my opinion, can also be find in the docs, under customizing-trigger-behavior.
Starting from that example, if you need your trigger to be totally separated from the container an option is to just wrap everything in a big container that receives ({ ref, ...triggerHandler }) and all is left is to give your container the ref, and the trigger to your FaUser component. So something like:
<OverlayTrigger
placement="bottom"
overlay={<Tooltip id="button-tooltip-2">Check out this avatar</Tooltip>}
>
{({ containerRef, ...triggerHandler }) => (
<Container fluid className='flex-fill' ref={containerRef}>
...
<FaUser/>
</Container>
)}
</OverlayTrigger>
I also created a sandbox with a minimal reproducible example.

when should I pass 'className' props to react component?

Some react components pass the className props to the child component.
I haven't seen any need for passing className as a prop in my projects.
why this className props is been used ? and when should i adopt this approach?
import styled from 'styled-components'
const ReactComponent = ({ className }) => {
return <div className={className}/>
}
const StyledComponent = styled(ReactComponent)``;
It really depends on the context, but generally, the className prop is passed down from parent to child to either overwrite, or append the existing className on the child component.
This is particularly useful in the scenario when you are building reusable base components which needed to be easily extended and customised.
Given your example,
const ReactComponent = ({ className }) => {
return <div className={className}/>
}
Let's say we have a parent component which renders the child ReactComponent, and we need to customise the stylings for this instance:
return (
<div className='container'>
<ReactComponent className='is-red' />
<ReactComponent className='is-blue'/>
</div>
)
This will allow the parent to render both components, with different styles, and without the need to repeat the same code.
You generally add classes to create a style or JavaScript code snippet that effects more than one element. Here is an explanation of how to use classes.
This particular component uses StyledComponent, but it's possible that the user wanted to add a class to add extra styles on top of those for the default in specific cases.
It's also possible that the classes are used to toggle some effect in JS. I've linked examples of each case.
Without more code it's hard to say why this particular user passed down a className, but there are certainly cases where you could want to, or when you could do without passing down a className. If your code doesn't seem to require it, there's definitely no reason to add it in.

How to use MenuItem as a NavLink?

I am trying to use a menu list to navigate through my application. Although, the app and routes are working fine i get some warnings in console using this piece of code :
{props.itemList.map((item, index) =>(
<div key={index}>
<MenuItem component={NavLink} to={item.to} onClick=
{handleClose} activeClassName={classes.topNavLinkActive}
className={classes.topNavLink}>
{item.name}
<Icon className={classes.navIcon}>{item.icon}</Icon>
</MenuItem>
</div>
))}
The warnings I get are :
Warning: Failed prop type: Invalid prop component supplied to ForwardRef(ButtonBase). Expected an element type that can hold a ref. Did you accidentally provide a plain function component instead?
index.js:1375 Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Can someone please explain why forward referencing is required here?
It seems like the error is about misusing the component property. The docs say:
The component used for the root node. Either a string to use a DOM element or a component.
According to MenuItem API, component property is of type elementType. The type definition file would show it's implementing JSX.IntrinsicElements interface (Which describe standard HTML tags).
NavLink element is a React component. Try providing a standard html tag name (string) or an actucal DOM node referance instead.

React onClick on stateless component

I have been trying to fire an onClick on a react component. The event fires if I use
<button onClick={()=>this.goToPage('next')}>Next Page</button>
If I use the same method on a stateless component, it doesn't fire:
<PageButton onClick={()=>this.goToPage('next')}>Next Page</PageButton>
Why this is not possible?
Because what you are defining is a custom component. Note, that everything that you provide to the custom component is considered as props. So, your onClick method is also provided as props. Essentially you'll be required to do -
<PageButton onClick={()=>this.goToPage('next')}>Next Page</PageButton>
and in your <PageButton /> component -
<button onClick={this.props.onClick}>Next Page</button>
if you know what props you are providing to this component and not providing any unnecessary props, you can even spread the props object, like -
<button {...this.props}>Next Page</button>
Note - If you have other props to provide to this component as well, kindly refrain from using this method, as this will result in many unrecognized function warnings.
PS: Even if you write
<PageButton style={{backgroundColor: 'red}}>Next Page</PageButton>
it won't work because, this is treated as a prop. You'll need to handle the style prop in the render method of this <PageButton/> component
This does not work on a stateless component because the onClick is considered as a prop rather a event listener , you should implement.
For example inside PageButton you should implement something like this
render(){
return <div onClick={()=>this.props.onClick('next')}/>
}

ReactDOM.render does not update containers props

I have a container containing some html with a <div id="ID"></div>. I have a react stateful component that I want to render in that div using
React.render(<ChildComponent data={this.props.data} />, document.getElementById('ID'))
When I call an action in childcomponent and udate the redux state, the props of the parent container do not update, only the ChildComponent re-renders with old values. Those props get updated when I refresh the page.
What is the solution to this ? Is there any other way to render React component in html so that the props can be updated with new props ?
Can you share your code for <ChildComponent> and its parent? There are a number of things you might be doing wrong but the thing that stands out is that it looks like you're rendering separately from its parent instead of as a child "prop" of its parent, like so:
<ParentComponent>
<ChildComponent />
</ParentComponent>
The official docs also have a lot of examples on how to get started: https://facebook.github.io/react/docs/hello-world.html
Hope this helps!

Resources