React - Get the component name in functional components - reactjs

I want on every component in my app to add attribute component-name="componentX". I don't want to do it hard coded when creating a component but to find a generic way to find the component name and set it in the attribute.
I know there is the displayName property but it's only for class component.
I have a lot of functional components. How can I achieve it?
Thanks!

If you wrap children you can access the child.type.name to get the component / function name.
Here is a small example:
class LogNames extends React.Component {
render() {
const { children } = this.props;
React.Children.forEach(children,child =>{
console.log(child.type.name)
});
return children;
}
}
class Child extends React.Component {
render() {
return <div>A Child</div>
}
}
const Child2 = () => <div>Child 2</div>
class App extends React.Component {
render() {
return (
<div>
<LogNames>
<Child/>
</LogNames>
<LogNames>
<Child2 />
</LogNames>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root" />
Just noticed you want to set an attribute on the DOM as well, so i added another example that does just that (open devtools to see the attributes):
class WithNameAttr extends React.Component {
componentDidMount(){
const {children} = this.props;
// get a ref to the current node
const node = ReactDOM.findDOMNode(this);
// force and return a signle child
const child = React.Children.only(children);
// set name attribute (if available)
const name = child.type.name;
name && node.setAttribute('component-name', name);
}
render() {
return this.props.children;
}
}
class Child extends React.Component {
render() {
return <div>A Child</div>
}
}
const Child2 = () => <div>Child 2</div>
class App extends React.Component {
render() {
return (
<div>
<WithNameAttr>
<Child />
</WithNameAttr>
<WithNameAttr>
<Child2 />
</WithNameAttr>
<WithNameAttr>
<div>dom elemetns doesnt have names</div>
</WithNameAttr>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"/>

Related

Is there a way of passing props to class component?

I'm a beginner in React.
I still quite don't understand how to pass props to a class component like we do in a function.
Example of a function:
const SurveyFormReview = ({ onCancel, formValues, submitSurvey, history }) => {
return (
...
<button
onClick={() => submitSurvey(formValues, history)}
className="green btn-flat right white-text"
>
...
);
};
Example of a class Component:
class ImageUpload extends Component {
render() {
return (
// I want to use props in here
)
}
}
For example
<ImageUpload propExample="property" />
Inside ImageUpload component you can access it by writing:
this.props.propExample
Just use whatever attributes you want when using the ImageUpload component:
<ImageUpload propA="someValue" propB={someVariable}/>
From the ImageUpload component, just call the props property:
someFunction = () => {
var propAValue = this.props.propA;
var propBValue = this.props.propB;
}
That's it!
You can pass any value as a props in Class and functional components in react. Read more about props
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
};
ReactDOM.render(
<Welcome name="Sara" />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>

react component render method being called twice for no reason

import './App.css';
import SolarSystem from './components/solarSystem/solarSystem';
class App extends React.Component {
componentDidMount(){
console.log("mounting");
}
componentDidUpdate(){
console.log("updating");
}
//const [SSVisibility, setSSVisibility] = useState(true);
render(){
console.log("rendering app");
return (
<div className="App">ssssssssssssssssssssssssssssssss
{/* <SolarSystem isShowing={"yolo"} toggle={"polo"}></SolarSystem> */}
</div>
);
}
}
export default App;
With this simple code, my render method is being called twice. And i cant understand why
It is because of strict mode, code below doesn't demonstrate it because SO will build it with production set true (I think).
class Strict extends React.Component {
componentDidMount() {
console.log('mounting strict');
}
componentDidUpdate() {
console.log('updating');
}
//const [SSVisibility, setSSVisibility] = useState(true);
render() {
console.log('rendering strict');
return (
<div className="App">
{/* <SolarSystem isShowing={"yolo"} toggle={"polo"}></SolarSystem> */}
</div>
);
}
}
class NonStrict extends React.Component {
componentDidMount() {
console.log('mounting non strict');
}
componentDidUpdate() {
console.log('updating');
}
//const [SSVisibility, setSSVisibility] = useState(true);
render() {
console.log('rendering Non strict');
return (
<div className="App">
{/* <SolarSystem isShowing={"yolo"} toggle={"polo"}></SolarSystem> */}
</div>
);
}
}
const App = () => {
return (
<div>
<React.StrictMode>
<Strict />
</React.StrictMode>
<NonStrict />
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

function doesn't call from one class to another class in react js

I am newbie in react js, so i appologies for this type of error, here i have created 2 class, Test1 and Test2, I want to call function_two function from class 1, but it doesn't working, can anyone please help me for this issue, here is my full code for that
class Test1 extends React.Component {
function_one() {
<Test2 function_two={this.function_two} />
}
render() {
return (
<h1>{this.function_one}</h1>
);
}
}
class Test2 extends React.Component {
function_two() {
return "Funtion 2";
}
}
//CallCRUD
ReactDOM.render(
<Test1 />, document.getElementById('root')
);
Two things :
You forgot to call your function : this.function_one should be this.function_one()
You did not return anything in function_one (you forgot the return statement)
Working fix :
class Test1 extends React.Component {
function_two(origin) {
console.log('Hello, from ' + origin)
}
function_one() {
return <Test2 function_two={this.function_two} />
}
render() {
return (
<h1>{this.function_one()}</h1>
);
}
}
class Test2 extends React.Component {
componentDidMount() {
this.props.function_two('Test2')
}
render = () => <div/>
}
ReactDOM.render(
<Test1 />, document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.3.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.0/umd/react-dom.production.min.js"></script>
<div id='root'/>
EDIT :
If your objective is to simply render something in your h1 tag you could do the following :
class Test1 extends React.Component {
function_one() {
return <Test2/>
}
render() {
return (
<h1>{this.function_one()}</h1>
);
}
}
class Test2 extends React.Component {
render(){
return <div>Hi, I'm Test2</div>
}
}
ReactDOM.render(
<Test1 />, document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.3.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.0/umd/react-dom.production.min.js"></script>
<div id='root'/>
Shorter syntax :
const Test1 = () => <h1><Test2/></h1>
const Test2 = () => <div>Hi, I'm Test2</div>
ReactDOM.render(
<Test1 />, document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.3.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.0/umd/react-dom.production.min.js"></script>
<div id='root'/>

Can we pass event name as props in react?

Hi I am new to react and I am trying to create a component where we can pass event name(onclick, onChange etc.) as props. So the component can be customize in an event way as well. Is it possible?
<Input {this.props.eventName} = {this.props.name} />
This I want to do. Is it possible?
Do you want to achieve something similar to this -
One problem is that you must pass only supported events to the element type.
e.g in case of button onClick and other events supported by button.
class Parent extends React.Component {
render() {
return(
<ChildComponent
evtName = 'onClick'
evtHandler={ () => { console.log("event called!");}}
/>
)
}
}
class ChildComponent extends React.Component {
render() {
return React.createElement(
'button',
{ [this.props.evtName] : this.props.evtHandler },
'Click me'
); }
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
If I understand you correctly, just pass the event and it's handler as props. I didn't see the use case just considering the event name.
See the below example of reusing the same element with different events.
class Input extends React.Component {
render(){
const {} = this.props;
return (
<input {...this.props} />
);
}
}
class Test extends React.Component {
render(){
return (
<div>
<Input name="onClick" onClick={(e) => console.log(e.target.name)}/>
<Input name="onChange" onChange={(e) => console.log(e.target.name)}/>
</div>
);
}
}
ReactDOM.render(<Test />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Here is example how to pass an event from parent Component to Child - by having result in Parent Component.
class Parent extends Component {
//constructor, other methods, etc...
// We call our event update
update(stuff) {
console.log(stuff);
}
}
We pass in ParentComponent's render method a ChildComponent with props onClick(you can name it whatever you want).
<ChildComponent
onClick={this.update.bind(this)}
/>
Now, ChildComponent. To access our props onClick, we just use this.props.onClick. Our argument is just hello, you can pass as many arguments you want.
<button onClick={ (e) => this.props.onClick('hello') }>
Action
</button>
Here is working example:
class Parent extends React.Component {
update(stuff) {
console.log(e, stuff);
}
render() {
return(
<ChildComponent
onClick={this.update.bind(this)} />
)
}
}
class ChildComponent extends React.Component {
render() {
return(
<div>
<button onClick={ (e) => this.props.onClick('hello') }> Action</button>
</div>
)
}
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

How to focus a input field, which is located in a child component

I have a button in a parent component. I want to focus an input field, which is located in a child component, by clicking on that button. How can I do it.
You can make use of refs to achieve the result
class Parent extends React.Component {
handleClick = () => {
this.refs.child.refs.myInput.focus();
}
render() {
return (
<div>
<Child ref="child"/>
<button onClick={this.handleClick.bind(this)}>focus</button>
</div>
)
}
}
class Child extends React.Component {
render() {
return (
<input type="text" ref="myInput"/>
)
}
}
ReactDOM.render(<Parent/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
UPDATE:
React docs recommend on using a ref callback rather than string refs
class Parent extends React.Component {
handleClick = () => {
this.child.myInput.focus();
}
render() {
return (
<div>
<Child ref={(ch) => this.child = ch}/>
<button onClick={this.handleClick.bind(this)}>focus</button>
</div>
)
}
}
class Child extends React.Component {
render() {
return (
<input type="text" ref={(ip)=> this.myInput= ip}/>
)
}
}
ReactDOM.render(<Parent/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Instead of accessing the child component's input element from parent, it's better to expose a method as below,
class Parent extends React.Component {
handleClick = () => {
this.refs.child.setFocus();
};
render() {
return (
<div>
<Child ref="child"/>
<button onClick={this.handleClick.bind(this)}>focus</button>
</div>
)
}
}
class Child extends React.Component {
setFocus() {
this.refs.myInput.focus();
}
render() {
return (
<input type="text" ref="myInput"/>
)
}
}
ReactDOM.render(<Parent/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Resources