React - How to pass props to a component passed as prop - javascript

I have a React component (React v15.5.4) that you can pass other components to:
class CustomForm extends React.Component {
...
render() {
return (
<div>
{this.props.component}
</div>
);
}
}
And I have a different component that uses it:
class SomeContainer extends React.Component {
...
render() {
let someObjectVariable = {someProperty: 'someValue'};
return (
<CustomForm
component={<SomeInnerComponent someProp={'someInnerComponentOwnProp'}/>}
object={someObjectVariable}
/>
);
}
}
Everything renders fine, but I want to pass someObjectVariable prop to the child component inside CustomForm (in this case that'll be SomeInnerComponent), since in the actual code you can pass several components to it instead of just one like the example.
Mind you, I also need to pass SomeInnerComponent its own props.
Is there a way to do that?

You can achieve that by using React.cloneElement.
Like this:
class CustomForm extends React.Component {
...
render() {
return (
<div>
{React.cloneElement(this.props.component,{ customProps: this.props.object })}
</div>
);
}
}
Working Code:
class Parent extends React.Component{
render() {
return(
<Child a={1} comp={<GChild/>} />
)
}
}
class Child extends React.Component{
constructor(){
super();
this.state = {b: 1};
this.updateB = this.updateB.bind(this);
}
updateB(){
this.setState(prevState => ({b: prevState.b+1}))
}
render(){
var Comp = this.props.comp;
return (
<div>
{React.cloneElement(Comp, {b: this.state.b})}
<button onClick={this.updateB}>Click to update b</button>
</div>
);
}
}
const GChild = props => <div>{JSON.stringify(props)}</div>;
ReactDOM.render(
<Parent />,
document.getElementById('container')
);
<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='container' />

You can do in the same as you did for SomeInnerComponent.
Just pass named props.
Inside CustomForm,
render() {
const MyComponent = this.props.component; //stored it in some variable
return (
<div>
<MyComponent customProps = {this.props.object} /> //access object here and passed it or passed individual props
</div>
);
}
EDIT :
Please find the working demo here.

You have a couple of options to achieve what your asking.
class SomeContainer extends React.Component {
...
render() {
let someObjectVariable = {someProperty: 'someValue'};
return (
<CustomForm
component={<SomeInnerComponent propFromParent={someObjectVariable}/>}
object={someObjectVariable}
/>
);
}
}
Or you can clone the component prop and apply the new props as Mayank said. In your case
class CustomForm extends React.Component {
...
render() {
return (
<div>
{React.cloneElement(this.props.component,
{propFromParent:this.props.someObjectVariable})}
</div>
);
}
}

You can use react-overrides for this.
Create CustomForm:
import o from "react-overrides";
const InnerComponent = () => null; // default
class CustomForm extends React.Component {
...
render() {
return (
<div>
<InnerComponent {...o} />
</div>
);
}
}
Pass props and component of InnerComponent at overrides prop:
class SomeContainer extends React.Component {
...
render() {
let someObjectVariable = {someProperty: 'someValue'};
return (
<CustomForm
object={someObjectVariable}
overrides={{
InnerComponent: {
component: SomeInnerComponent,
props: {
someProp: 'someInnerComponentOwnProp'
}
}
}}
/>
);
}
}

<TextField place={"India"}> </TextField>
and in your component TextField
class TextField extends Component {
constructor(props){
super(props);
}
render() {
return (
<div>
<input />
<button> {this.props.place} </button>
</div>
)
}
}

i think what you are trying to achieve is something like this you have to pass your InnerComponent as an arrow function () => ..
class SomeContainer extends React.Component { ... render() {
let someObjectVariable = {someProperty: 'someValue'};
return (
<CustomForm
component={() => <SomeInnerComponent someProp={'someInnerComponentOwnProp'}/>}
object={someObjectVariable}
/>
); } }

Related

I want to create some program with react js, about adding strings in window, but I am having an error

I am creating a program with React Js, where I need to write something in prompts and it needs to appear in window. Now I have created the function of adding prompts and pasting it in window, but it's giving an error.
please help me if you can : )
export default class Clock extends React.Component {
state = {items: ['Hakob', 'Arman']};
Add(){
const newitems = this.state.items.concat([prompt('a')])
this.setState({items:newitems})
}
render(){
return <div>
<Clock2/>
</div>
}
}
class Clock2 extends React.Component {
render(){
return(
<>
<button onClick={this.Add}>click</button>
<div> {this.state.items.map((e, i) => {
return <div key = {e + i}> {e} </div>
} )} </div>
</>
)
}
}
you have not defined any state in class clock2 so, the line # 798 giving you an error for cannot read property of items as it is not defined in class
class Clock2 extends React.Components {
state = {
items : //
}
}
and the second error is you are trying to return in the return function that is not correct if you want to map items you have to define map function in render
{
const items = this.state.items.map((e,i ) => {
//
}
return (
<items/>
)
So let's write your code here.
export default class Clock extends React.Component {
state = { items: ['Hakob', 'Aram']};
Add() {
const newItems = this.state.items.concat([prompt('a')])
this.setState({items:newItems})
}
render() {
return <div><Clock2/><div>
}
}
class Clock2 extends React.Component {
render() {
return (
<>
<button onClick={this.Add}>Click</button>
<div>{ this.state.items.map( (e,i) => {
return <div key={ e + i}>{e}</div>
})}
</div>
</>
)
}
}
You made a mistake, state are internals to component, as well as method.
This should work
export default class Clock extends React.Component {
state = { items: ['Hakob', 'Aram']};
Add() {
const newItems = this.state.items.concat([prompt('a')])
this.setState({items:newItems})
}
render() {
return (
<>
<button onClick={this.Add}>Click</button>
<div>{ this.state.items.map( (e,i) => {
return <div key={ e + i}>{e}</div>
})}
</div>
</>
)
}
}
Or you can pass values from top component to his child.
export default class Clock extends React.Component {
state = { items: ['Hakob', 'Aram']};
Add() {
const newItems = this.state.items.concat([prompt('a')])
this.setState({items:newItems})
}
render() {
return (<div><Clock2 add={this.Add} values={this.state.items}/><div>)
}
}
class Clock2 extends React.Component {
render() {
return (
<>
<button onClick={this.prop.add}>Click</button>
<div>{ this.props.values.map( (e,i) => {
return <div key={ e + i}>{e}</div>
})}
</div>
</>
)
}
}

What is the difference between this.state.function and this.function in ReactJS

I am learning the concept of States in React. I am trying to understand the difference between using this.handleChange, and this.state.handleChange.
I would be grateful if someone could explain to me, the exact difference between the two, and why would this.state.handleChange not work?
class MyApp extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: ''
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
inputValue: event.target.value
});
}
render() {
return (
<div>
< GetInput input={this.state.inputValue} handleChange={this.handleChange} />
{ /* this.handleChanges, and this.state.handleChanges */ }
< RenderInput input={this.state.inputValue} />
</div>
);
}
};
class GetInput extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>Get Input:</h3>
<input
value={this.props.input}
onChange={this.props.handleChange}/>
</div>
);
}
};
class RenderInput extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>Input Render:</h3>
<p>{this.props.input}</p>
</div>
);
}
};
You can technically call this.state.handleChange so long as you add handleChange in your state.
But it doesn't really make sense since you don't want React to keep a track of it, and it will probably not change (unless you are doing some clever tricks).
constructor(props) {
super(props);
this.state = {
handleChange: e => {
e.preventDefault();
console.log("this.state.handleChange");
}
};
}
One would normally declare a member function in a class.
handleChange = e => {
e.preventDefault();
console.log("this.handleChange");
};
Here is the full working code
(working demo available on CodeSandBox).
import React from "react";
import ReactDOM from "react-dom";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
handleChange: e => {
e.preventDefault();
console.log("this.state.handleChange");
}
};
}
handleChange = e => {
e.preventDefault();
console.log("this.handleChange");
};
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<button onClick={this.handleChange}>this.handleChange</button>
<button onClick={this.state.handleChange}>
this.state.handleChange
</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
When you say this.state.something this means something is in the state field of the class. When you say this.someFunction this means something is in the class itself. this here is pointing out our class.
class App extends React.Component {
state = {
something: "Something",
}
someFunction = () => console.log(this.state.something);
render() {
return (
<div>
<button onClick={this.someFunction}>Click</button>
</div>
);
}
}
ReactDOM.render(
<App />,
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>
So, you can't use this.state.handleChange since there is no handleChange in the state. It is a function belongs to the class. This is why we use this.handleChange.
you can store a function in state
constructor(super){
super(props)
this.state = {
generateANumber: () => this.setState({ number: Math.floor(Math.random() * 100) }),
number: 0
}
}
then if you want to call it in your render method
render() {
return <p> {this.state.number} <button onClick={() => this.state.generateANumber()} Press Me To Generate A New Number </button> </p>
}
This is the concept of storing a function in state. This.function just means the function belongs to that class so you can use it using the this keyword.

Update the state of the grandparent component

I'd like to update a state value of the grandparent component:
class GrandChild extends React.Component {
changeNumber() {
// this.setState(prevState => ({
// number: prevState.number + 1 // Add 1
// }));
// I want to set the state of the App Component instead of the GrandChild component
}
render() {
return(
<div>
<h1>The number is {this.props.number}</h1>
<button onClick={this.changeNumber}>Increase number by 1</button>
</div>
)
}
}
class Child extends React.Component {
render() {
return(
<div>
<GrandChild number={this.props.number}/>
</div>
)
}
}
class App extends React.Component {
constructor() {
super()
this.state = {
number: 1
}
}
render() {
return (
<Child number={this.state.number}/>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
I did code this in CodePen for those who want to test the code: https://codepen.io/anon/pen/oEeQdr
I hope there's a simple solution for this.
Thanks in advance.
class GrandChild extends React.Component {
changeNumber=()=> {
this.props.changeNumber();//call parent `changeNumber` method
}
render() {
return(
<div>
<h1>The number is {this.props.number}</h1>
<button onClick={this.changeNumber}>Increase number by 1</button>
</div>
)
}
}
class Child extends React.Component {
render() {
return(
<div>
<GrandChild number={this.props.number} changeNumber={this.props.changeNumber} /> //passed `changeNumber` as it is to `GrandChild`
</div>
)
}
}
class App extends React.Component {
constructor() {
super()
this.state = {
number: 1
}
}
changeNumber=()=>{
this.setState((prevState)=>{
console.log(prevState);
return {
number : prevState.number + 1
}
});
}
render() {
return (
<Child number={this.state.number} changeNumber = {this.changeNumber}/> //passed `changeNumber` to Child
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Working codepen
Check working code below:
import React from 'react';
import ReactDOM from 'react-dom';
class GrandChild extends React.Component {
render() {
return (
<div>
<h1>The number is {this.props.number}</h1>
<button onClick={this.props.incNumber}>Increase number by 1</button>
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
<GrandChild number={this.props.number} incNumber={this.props.incNumber} />
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
number: 1
};
}
incrementNumber = () => {
this.setState({ number: this.state.number + 1 });
};
render() {
return (
<Child number={this.state.number} incNumber={this.incrementNumber} />
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
You can send method body as a prop to Child Class, as a pointer to it, and when you wil lcal this method in the Child, it will properly executed in the Parent, where was declared.
class GrandChild extends React.Component {
render() {
return (
<div>
<h1>The number is {this.props.passedProps.number}</h1>
<button onClick={() =>
this.props.passedProps.increaseNumber()}>Increase number by 1</button>
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
<GrandChild passedProps={this.props}/>
</div>
);
}
}
class App extends React.Component {
constructor() {
super()
this.state = {
number: 1
}
}
increaseNumber = () => {
this.setState({ number: this.state.number + 1 });
}
render() {
return (
<Child number={this.state.number} increaseNumber={this.increaseNumber}/>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));

Why props render as undefined?

I have this React-component called PersonCard:
class PersonCard extends Component {
constructor(props) {
super(props);
console.log(JSON.stringify(props));
this.state = props;
}
render() {
return (
<div>
<MuiThemeProvider muiTheme={Mui} >
<Card>
<CardHeader
title={this.props.firstName}
/>
</Card>
</MuiThemeProvider>
</div>
);
}
}
export default PersonCard;
The view has multiple PersonCards and they're mapped from an array in its parent component SearchResults as follows:
class SearchResults extends Component {
constructor() {
super()
this.state = {
data: [],
}
}
componentDidMount() {
return fetch('http://localhost:3005/persons')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
data:responseJson
})
})
}
render() {
return (
<div>
{
this.state.data.map( (person)=>
<PersonCard key={person.id} personProp = {person} />
)
}
</div>
)
}
}
export default SearchResults;
The logger in the constructor shows the person objects and their properties correctly, so it's there as it should be.
BUT the props value (this.props.firstName) doesn't show in the render-method, since they get rendered as "undefined" on the view. Why?
You don't define a prop called firstName here:
<PersonCard key={person.id} personProp = {person} />
Maybe you meant to access it through this.props.personProp.firstname?
In your code you are pass "key" and "personProp" props to "PersonCard" components. So inside the render function of "PersonCard" component you can access these props by "this.pops.key" and "this.props.personProp".
So if your personProp contain's the firstName then you will be able to access it by "this.prps.personProp.firstName". So you should try below code
class PersonCard extends Component {
constructor(props) {
super(props);
console.log(JSON.stringify(props));
this.state = props;
}
render() {
return (
<div>
<MuiThemeProvider muiTheme={Mui} >
<Card>
<CardHeader
title={this.props.personProp.firstName}
/>
</Card>
</MuiThemeProvider>
</div>
);
}
}
export default PersonCard;

My component doesn't rerender

When I click on button, I see '1' in console, but never see '2'. Why it happens? Can you help me please to resolve this issue? I realy dont know why my second component doesn't update.
class App extends PureComponent {
constructor() {
super();
this.state = {
name: 'Vasya'
}
this._onChange = this._onChange.bind(this);
}
_onChange(name) {
this.setState({
name: name
});
}
render() {
console.log(1);
return {
<div>
<Button onClick={this._onChange('Petr')} />
<AnotherComponent username={this.state.name} />
</div>
}
}
}
class AnotherComponent extends PureComponent {
const {
username
} = this.props
render() {
console.log(2);
return {
<div>
test
</div>
}
}
}
export default App;
A few code problems in your example!
when you return your React elements from render(), they must be wrapped in parens () not curlies {}
use React.Component, not React.PureComponent, or you'll get issues
<Button> isn't a thing, use <button>
The main problem then is an infinite loop - when you render, this line:
<Button onClick={this._onChange('Petr')} />
...this calls the _onChange() function at render time and passes the result to Button as the onClick prop. This isn't what you want - you want the onClick prop to be a function that calls _onChange(). So
<button onClick={ () => this._onChange('Petr')} />
Full working example:
class App extends React.Component {
constructor() {
super();
this.state = {
name: 'Vasya'
}
this._onChange = this._onChange.bind(this);
}
_onChange(name) {
this.setState({
name: name
});
}
render() {
console.log(1);
return (
<div>
<button onClick={ () => this._onChange("Petr") } />
<AnotherComponent username={this.state.name} />
</div>
);
}
}
class AnotherComponent extends React.Component {
render() {
console.log(2);
return (
<div>
test
</div>
);
}
}
ReactDOM.render(<App />, 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>

Categories

Resources