Transfer component in props with children method - javascript

Its possible to transfer component in props with children method?
I have to components:
let a = (<div>
<button onClick={TContainer.METHOD}>TuCLIK</button>
</div>);
<TContainer data={ restaurantList } component={a}/>
I want to call method in childen but create element in parent. I want to pass this component on props.
If its possible i dont know what writing in TContainer.METHOD to call childen method

You are not passing a component in your props, it's an expression.
A component should be either a class the extends React.Component or a function that returns a jsx markup.
Now when we know that components are just functions, we know that we can pass parameters to them, hence we can pass a function reference as a parameter:
let A = (onClick) => <div><button onClick={onClick}>TuCLIK</button></div>;
<TContainer data={ restaurantList } component={<A onClick={TContainer.METHOD} />}/>
Note that components should be capitalized.
Edit
As a followup to your comment, sorry but i misunderstood your question i guess.
You can't pass a reference of a method from a React component like that.
We can use couple of approaches regarding this scenario, one of them
is to use this.props.children and pass the child component as a
child.
For example - <Parant><Child/></Parent>
We can pass the child component as a prop.
For example - <Parent component={Child} /> or <Parent component={<Child />} />
We can write the parent component as a HOC and wrap the child
with it.
For example - Parent(Child)
In all the above examples you can't pass directly a reference of a function that is declared inside the parent's scope (as a prop to the child).
In order to pass the child a prop within the parent's internal scope you should do it inside the render method.
For example:
render() {
return (
<div>
<this.props.component onClick={this.handleClick}/>
</div>
);
}
This is a snippet that demonstrate one of the examples above:
const Child = ({onClick}) => <div onClick={onClick}>Im a child, Click me!</div>
class Parent extends React.Component {
constructor(props){
super(props);
this.state = {
counter: 0
}
this.addCount = this.addCount.bind(this);
}
addCount(){
this.setState({counter: this.state.counter + 1});
}
render() {
return (
<div>
<div>{`Count = ${this.state.counter}`}</div>
<this.props.component onClick={this.addCount}/>
</div>
);
}
}
const App = () => <Parent component={Child} />;
ReactDOM.render(<App />, 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>

Related

How can I pass a component as a prop into another component in React?

I am new to React and I have a Java background, so forgive if the wording of this question doesn't really make sense.
I would like to "pass" an instance of a component into another component (that uses the passed component in it's render() method)
How can I do this?
Sorry for the bad naming, but I hope you're able to see the different use cases from what I understand from your question:
// Component that receives another component being passed in its props
function Renderer1(props) {
return props.component
}
// Component that receives another component and creates an instance of it
// this way this component has more control of rendering the passed component
// and the props you want to pass to it
function Renderer2(props) {
return <props.component />
}
// Component being passed in props
function PropComponent(){
return <div>Hello world!</div>
}
// Rendered component, example 1
function Main1() {
return <Renderer1 component={() => <PropComponent />} />
}
// Rendered component, example 2, this one uses Renderer2 component
function Main2() {
return <Renderer2 component={PropComponent} />
}
I hope with these different examples you can get an idea of how to continue with what you're working on :)
The question is not very clear. But from what I understand, there can be multiple ways of doing this.
Component 1
class Component1 extends React.Component {
render() {
return <h1>Component 1</h1>;
}
}
Component 2
class Component2 extends React.Component {
render() {
return (
<React.Fragment>
<h1>Component 2</h1>
{children}
</React.Fragment>
}
}
MainComponent
class MainComponent extends React.Component {
render() {
return (
<Component2>
<Component1 />
</Component2>
}
}
Here, one 'instance' of Component1 is passed to Component2 which then renders the Component1 as one of its children.
Another way is to use Render Props. To understand Render Props in a better way, you can watch this Youtube tutorial.

React: How to do conditional checks from render() method in functional Components?

In my normal React class Components, I have done some checks in the render() method, before returning conditional html rendering. Now, I was using a react functional component, which apparently does not have the render() method... how would I do the conditional checks here? Just Inside normal functions and then return html code from those functions?
e.g Class Component:
render() {
let test;
if (this.state.test ===true) {
test = (
<p>This is a test</p>
)
}
return(
{test}
)
}
in functional components? :
return (
<p >
{checkIcon()} //normal Javascript functions?
</p>
)
As stated by others you can do anything inside a render function, the same things you could do with a class component. You can think of your functional components as the render function of your class ones...
Functional components, by the way, should not contain that much business logic, it'd be better to enhance them with HOCs and function composition.
You might want to have a look at recompose, in which my example takes inspiration from. (change the test attribute and press run code snippet)
// First create a Generic HOC that embedds the branching logic for you.
const branch = (predicate, LeftComponent) => RightComponent => props => (
predicate(props) ? <LeftComponent {...props} /> : <RightComponent {...props} />
);
// Leave your view component the only job of displaying data to the screen. Avoid any control flow.
const Test = () => 'this is a test component';
const Value = ({ value }) => <div>The Value is {value}</div>;
// Create a final component that branches accordingly with the needed check (if props.test is true)
const Component = branch(
props => props.test,
Test
)(Value);
ReactDOM.render(
<Component test={true} value="£100" />,
document.getElementById('container')
);
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="container"></div>
You can think of functional component as a render method of class component where you can do the exact same thing that you do in render except that you will receive props from the arguments instead of this and similarly you won't have state unless your using hooks. So you would pass test as a prop to the functional component
const MyComponent = ({test}) =>{
let value;
if (test ===true) {
test = (
<p>This is a test</p>
)
}
return(
{value}
)
}

Passing data from child to parent, React.js

I'm trying to pass data from a child component up to a parent component. However, when doing so, I get the error:
Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount
I don't understand because when I use the same pattern with an event handler, everything is fine. How can I successfully pass data from the child component to the parent without getting the error?
const Child = (props) => {
let message = 'Hi mom'
props.callBackFromParent(message);
return <h3>{props.message}</h3>
};
class Parent extends React.Component {
constructor(props){
super(props)
this.state = {
messageFromChild: '',
}
this.callBackFromParent = this.callBackFromParent.bind(this);
}
callBackFromParent(dataFromChild){
this.setState({messageFromChild: dataFromChild})
}
render(){
return (
<div>
<h2>Message from Child is:</h2>
<Child
message={this.state.messageFromChild}
callBackFromParent={this.callBackFromParent}
/>
</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>
It's not allowed to call setState during rendering, which a call to props.callBackFromParent would result in.
You can use the function as an event handler instead, and it will set the state of the parent as expected.
Example
const Child = (props) => {
let message = 'Hi mom';
return <h3 onClick={() => props.callBackFromParent(message)}>{props.message}</h3>
};

Why does the React tutorial recommend that child Component states be stored in the parent Component?

According to the React tutorial at https://facebook.github.io/react/tutorial/tutorial.html:
When you want to aggregate data from multiple children or to have two
child components communicate with each other, move the state upwards
so that it lives in the parent component. The parent can then pass the
state back down to the children via props, so that the child
components are always in sync with each other and with the parent.
This seems to contradict good OOP practices where each object maintains it own state.
When you want to aggregate data from multiple children or to have two
child components communicate with each other, move the state upwards
so that it lives in the parent component. The parent can then pass the
state back down to the children via props, so that the child
components are always in sync with each other and with the parent.
Consider a case where a Parent has two children, with a structure as follows
<Parent>
<Child1/>
<Child2/>
</Parent>
Now Child1 just has the input component, and Child2 displays what was entered in the input say
In this case if you keep the value of the input in Child1, you cannot access it from the Parent as state is local to a component and is a private property . So it makes sense to keep the property in parent and then pass it down to child as props so that both children can use it
A sample snippet
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
inputVal: ''
}
}
handleChange = (val) => {
this.setState({inputVal: val});
}
render() {
return (
<div>
<Child1 handleChange={this.handleChange} inpVal={this.state.inputVal}/>
<Child2 value={this.state.inputVal}/>
</div>
)
}
}
class Child1 extends React.Component {
render() {
return (
<div>
<input type="text" value={this.props.inpVal} onChange={(e) => this.props.handleChange(e.target.value)} />
</div>
)
}
}
class Child2 extends React.Component {
render() {
return (
<div>
{this.props.value}
</div>
)
}
}
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"></app>

How to pass state back to parent in React?

I have a form that has a submit button.
That form calls a function onclick that sets the state of something from false to true.
I then want to pass this state back to the parent so that if it is true it renders componentA but if it is false it renders componentB.
How would I do that in react?
I know I need to use state or props but not sure how to do it. also is this contradicting the one-way flow react principle??
ComponentA code:
<form onSubmit={this.handleClick}>
handleClick(event) {
this.setState({ decisionPage: true });
event.preventDefault();
};
Parent component that controls what it displays:
return (
<div>
{this.props.decisionPage ?
<div>
<LoginPage />
</div>
:
<div>
<Decision showThanks={this.props.showThanks}/>
</div>
}
</div>
)
Move handleClick to the parent and pass it to the child component as a prop.
<LoginPage handleClick={this.handleClick.bind(this)}/>
Now in the child component:
<form onSubmit={this.props.handleClick}>
This way submitting the form will update the state in parent component directly. This assumes you don't need to access updated state value in child component. If you do, then you can pass the state value back from the parent to the child as a prop. One-way data flow is maintained.
<LoginPage handleClick={this.handleClick.bind(this)} decisionPage={this.state.decisionPage}/>
Pass State as a Prop
I have recently learned a method that works great for changing state in a <Parent /> component from a <Child /> component.
This might not be the exact answer for this question, but it is surely applicable to this situation and other similar situations.
It works like this:
set the default STATE in the <Parent /> component - Then add the 'setState' attribute to the <Child />
const Parent = () => {
const [value, setValue] = useState(" Default Value ");
return (
<Child setValue={setValue} />
)
}
Then change the state(in Parent) from the Child component
const Child = props => {
return (
<button onClick={() => props.setValue(" My NEW Value ")}>
Click to change the state
</button>
)
}
When you click the button, the state in the <Parent /> component will change to whatever you set the state to in the <Child /> component, making use of "props".. This can be anything you want.
I Hope this helps you and other devs in the future.
In Parent Component:
getDatafromChild(val){
console.log(val);
}
render(){
return(<Child sendData={this.getDatafromChild}/>);
}
In Child Component:
callBackMethod(){
this.props.sendData(value);
}
Simple Steps:
Create a component called Parent.
In Parent Component create a method that accepts some data and sets
the accepted data as the parent's state.
Create a component called Child.
Pass the method created in Parent to child as props.
Accept the props in parent using this.props followed by method
name and pass child's state to it as argument.
The method will replace the parent's state with the child's state.
Here is an example of how we can pass data from child to parent (I had the same issue and use come out with this )
On parent, I have a function (which I will call from a child with some data for it)
handleEdit(event, id){ //Fuction
event.preventDefault();
this.setState({ displayModal: true , responseMessage:'', resId:id, mode:'edit'});
}
dishData = <DishListHtml list={products} onDelete={this.handleDelete} onEdit={(event, id) => this.handleEdit(event, id)}/>;
At the child component :
<div to="#editItemDetails" data-toggle="modal" onClick={(event)=>this.props.onEdit(event, listElement.id) }
className="btn btn-success">
In React you can pass data from parent to child using props. But you need a different mechanism to pass data from child to parent.
Another method to do this is to create a callback method. You pass the callback method to the child when it's created.
class Parent extends React.Component {
myCallback = (dataFromChild) => {
//use dataFromChild
},
render() {
return (
<div>
<ComponentA callbackFromParent={this.myCallback}/>
</div>
);
}
}
You pass the decisionPage value from the child to the parent via the callback method the parent passed.
class ComponentA extends React.Component{
someFn = () => {
this.props.callbackFromParent(decisionPage);
},
render() {
[...]
}
};
SomeFn could be your handleClick method.
if your parent component is a functional component you can now use the use context way. Which involves passing the ref to the object and the ref to the stateChanging method. What this will allow you to do is change state from parrent in child and also ref tht state while remaining synced with Parent State. You can learn more about this in a youtubeVideo by codedamn titled 'React 16.12 Tutorial 20: Intro to Context API' and 'React 16.12 Tutorial 21: useContext'
This works exactly what I wanted. But in case of set of data with say 50 records with (customer_id, customer_name) as values to be updated from child to parent, then this lags. Do the setState using React.useEffect in child component
i have same problem and so performed this code :
in Parent
const PARENT = () => {
const [value, setValue] = useState("....");
return (
)
}
in Child
const CHILD = props => {
return (
<button onClick={() => props.setValue("....")}>
Click to change the state
</button>
)
}

Categories