How can I pass a prop from child to parent component - reactjs

How can I pass a prop (when modified) from Child Component to a Parent Component.
Some Details :
I am working on an existing codebase where I have Parent Component embedded in
'unstated.Container' and a separate Child Component , where I am trying to add a button. When
a user clicks this button some value gets updated , which needs to be passed to the Parent
component .
Thank you.
import {Container} from 'unstated';
class DelContainer extends Container{
state = { sortAsc : true, notified : null}
setVal = async (Id, value) => { console.log (`Id : ${Id}); console.log('value: ${value}); }
}
//Child Component (Separate file)
const ChildItems = (props) => {
const [some_value ] = props;
const [some_color, setColor] = useState(" ");
const MarkIt = ({some_value})
{
some_value = this.props.some_value; //ISSUE HERE
}
return (
<IconButton >
<StarOutlinedIcon onClick = {MarkIt} style={{color: `${some_color}`}}/>
</IconButton>
);
}
//Parent Component (Separate file)
import {Subscribe} from 'unstated';
const DelList = (props) => {
return(
<Subscribe to ={[DelContainer]}>
{
(delStore) => {
const[person, isLoading] = delStore.state;
return(
<div>
<List className = {props.className} isLoading = {Loading}>
{
isLoading && person
.map((person, index)=>{
return <ChildItem key={index}
person = {person}
some_value = {delStore.MarkIt(some_value)};
}
}
</List<
</div>
)
}
}
);
}

Read this :
How to update parent's state in React?
Reactjs DOCS:
https://reactjs.org/docs/lifting-state-up.html
class Parent extends React.Component {
liftStateHander=()=> {
this.setState({
name:"John"
})
}
render() {
return <Child handler={this.liftStateHander} />
}
}
class Child extends React.Component {
render() {
return (
<button onClick={this.props.handler}>
Click For Change State Parent
</button>
)
}
}

Related

Reuse same DOM element in two different react components

I have a small question.
Let's imagine I have component A which holds , after component A does it's job I render component B. I would like that same DOM element (textarea) would be reused in component B.
The reason is if new textarea is rendered in component B it loses focus as it's just new DOM element. It's like after component A lifetame take textarea element from it and just put it in component B instead of rendering new one.
Sample APP
https://jsfiddle.net/remdex/v67gqyLa/1/#&togetherjs=aiRvTGhRK2
class AComponent extends React.Component {
render() {
return ( <textarea>A Component</textarea> )
}
}
class BComponent extends React.Component {
render() {
return ( <textarea>Should be A Component text</textarea> )
}
}
class ABComponent extends React.Component {
constructor(props) {
super(props)
this.state = {'component' : 'A'};
}
render() {
return (
<div><button onClick={(e) => this.setState({component:'B'})}>Switch to B Component</button>
{this.state.component == 'A' && <AComponent/>}
{this.state.component == 'B' && <BComponent/>}
</div>
)
}
}
ReactDOM.render(<ABComponent />, document.querySelector("#app"))
In your sandbox example, ComponentA and ComponentB are redundant. You can create ComponentA and ComponentB as a class if they are using same element and operate them with ComponentAB. You can change your ComponentAB like:
class A {
handle(input) {
// Do your A job here and return result
console.log("Handler A is running");
};
}
class B {
handle(input) {
// Do your B job here and return result
console.log("Handler B is running");
};
}
class ABComponent extends React.Component {
currentHandler = new A();
handleClick = () => {
this.currentHandler = new B();
};
handleChange = (event) => {
// Handle the input with current handler
var result = this.currentHandler.handle(event.target.value);
// If you want you can use result to cahnge something in view
// this.setState({value: result});
}
render() {
return (
<div>
<button onClick={this.handleClick}>
Switch to B Component
</button>
<textarea onChange={this.handleChange}>Text Area used between A class and B class</textarea>
</div>
)
}
}
I also edit the codebox example. You can find it here.
This can be achieved using a ref. ABComponent passes a ref to BComponent to attach to the textarea. When the state of ABComponent updates to component = 'B', then the ref is used to set focus. Use a ref passed to AComponent to grab its textarea value before it's unmounted, then set the value of the textarea in B to it.
import React, { Component, createRef } from "react";
...
class AComponent extends Component {
render() {
const { textareaRef } = this.props;
return <textarea ref={textareaRef} defaultValue="A Component" />;
}
}
class BComponent extends Component {
render() {
const { textareaRef } = this.props;
return <textarea ref={textareaRef} defaultValue="Should be A Component text" />;
}
}
class ABComponent extends Component {
state = { component: "A" };
refA = createRef();
refB = createRef();
componentDidUpdate(prevProps, prevState) {
const { component, content } = this.state;
if (prevState.component !== component) {
if (component === "B") {
this.refB.current.focus();
this.refB.current.value = content;
}
}
}
render() {
return (
<div>
<button
onClick={e =>
this.setState({ component: "B", content: this.refA.current.value })
}
>
Switch to B Component
</button>
{this.state.component === "A" && <AComponent textareaRef={this.refA} />}
{this.state.component === "B" && <BComponent textareaRef={this.refB} />}
</div>
);
}
}

React passed data from child to parent not logging in parent

I tried to pass data from a child component to it's parent but it isn't showing in the parent component.
In parent component I want to display the duration of a service that is selected in the child component.
In the child component I can log the selected service but it isn't passing to its parent:
Parent component:
class CalenderModal extends React.Component {
state={selectedService:[]}
// handover of child data to parent
handleServiceSelect = (selectedServiceObj) => {
this.setState({selectedService: selectedServiceObj});
console.log('inside CalendarModal:', this.state.selectedService)
}
handleRemove = () => {
this.props.onRemove();
}
handleSave = () => {
const fullname = this.fullname.value;
const phone = this.phone.value;
this.props.onSave({
fullname,
phone,
});
}
render() {
return (
<div className="customModal">
<div>Choose service you want to schedule:</div>
/// child component
<ServiceSearch onServiceSelect={()=> this.handleServiceSelect}/>
<div>{this.state.selectedService.duration} hours</div>
<button className="customModal__button customModal__button_example" onClick={this.handleSave}>{action}</button>
</div>
);
}
}
export default CalenderModal;
Child component:
class ServiceList extends Component {
constructor(props) {
super(props);
}
servicesToRender=[]
handleServiceSelect = (event) => {
var selectedServiceId = event.target.value;
var selectedService = this.servicesToRender.find(({id})=> id === selectedServiceId )
console.log("inside Service search:",selectedService)
this.props.onServiceSelect(selectedService);
}
render() {
const FEED_QUERY = gql`
{
servicefeed {
id
name
cost
duration
}
}
`
return (
<Query query={FEED_QUERY} >
{({ loading, error, data }) => {
if (loading) return <div>Fetching</div>
if (error) return <div>Error</div>
this.servicesToRender= data.servicefeed
// const servicesToRender = data.servicefeed
return (
<React.Fragment>
<label class="my-1 mr-2" for="inlineFormCustomSelectPref">choose service:</label>
<select class="custom-select my-1 mr-sm-2" id="inlineFormCustomSelectPref" onChange={this.handleServiceSelect}>
{this.servicesToRender.map(service => <ServiceSearchOption key={service.id} service={service} />)}
</select>
</React.Fragment>
)
}}
</Query>
)
}
}
export default ServiceList
I'm not sure what I'm missing here.
You haven't called the function in parent when passing it as props and using arrow function inline. The correct ways is below
<ServiceSearch onServiceSelect={()=> this.handleServiceSelect()}/>
However, you could have simply passed the function reference without an arrow function since the handleServiceSelect is already and arrow function and will have function binding
<ServiceSearch onServiceSelect={this.handleServiceSelect}/>

ReactJS: Trigger event from child in parent component

i have two components: 1.Parent 2.Child
there is an event in child component called onChange() which return a value.
i want to receive the value which was returned from OnChange() in componentDidMount() in parent component.
Example:
class Parent extends PureComponent {
componentDidMount() {
let value = CHILD.onChange(); //triggered when ever onChange()
}
render(){
return(
<Child />
)
}
}
const Child = () => {
const onChange = () => {
const value = 1
return value;
};
}
class Parent extends PureComponent {
handleChildChange = value => {
//Do your stuff with value, pass it to the state and take it from there if you like
}
render(){
return(
<Child handleChange={this.handleChildChange} />
)
}
}
const Child = (props) => {
const onChange = () => {
value = 1
props.handleChange(value);
}
};
}

React Native Pass Parent Method to Child Component

I am trying to pass method from my parent component to child component. My code is correct i think but still it shows the error undefined is not an object(evaluating '_this2.props.updateData') . I don't know whats the issue because i searched the internet a lot and everyone is passing props to child like this. Kindly tell what am i missing
Parent:
class Parent extends React.Component {
updateData = (data) => {
console.log(`This data isn't parent data. It's ${data}.`)
// data should be 'child data' when the
// Test button in the child component is clicked
}
render() {
return (
<Child updateData={val => this.updateData(val)} />
);
}
Child:
class Child extends React.Component {
const passedData = 'child data'
handleClick = () => {
this.props.updateData(passedData);
}
render() {
return (
<button onClick={this.handleClick()}>Test</button>
);
}
}
`class Child extends React.Component {
handleClick = () => {
const passedData = 'child data'
this.props.updateData(passedData);
}
render() {
return (
<button onClick={this.handleClick}>Test</button>
);
}
}`
class Parent extends React.Component {
updateData = (data) => {
console.log(`This data isn't parent data. It's ${data}.`)
}
render() {
return (
<Child updateData={this.updateData} />
);
}
}
and child component: `
class Child extends React.Component {
const passedData = 'child data'
handleClick = () => {
this.props.updateData(passedData);
}
render() {
return (
<button onClick={this.handleClick}>Test</button>
);
}
}
`
You need to pass the function directly, not as a callback
class Parent extends React.Component {
updateData = (data) => {
console.log(`This data isn't parent data. It's ${data}.`)
// data should be 'child data' when the
// Test button in the child component is clicked
}
render() {
return (
<Child updateData={this.updateData} />
);
}
I think you need to pass a function like this. Check out this solution.

Can Father component show child component state ??

DragAndResizeBox.js
I use ref={(c) => { this.resizableandmovable = c; }} in ResizableAndMovable as the react-rnd document said
I found I can get this.resizableandmovable.state.x ,this.resizableandmovable.state.y
class DragAndResizeBox extends Component {
constructor(props) {
super(props);
}
onDragStop = (event, ui) => {
console.log("[onDragStop]state:",this.resizableandmovable.state)
}
render() {
const { canDrop, isOver, connectDropTarget } = this.props;
const isActive = canDrop && isOver;
const { contentObjectId, boxType } = this.props
return connectDropTarget(
<div>
<ResizableAndMovable
ref={(c) => { this.resizableandmovable = c; }}
initial = {{
x:this.props.axisX ? this.props.axisX: 0,
y:this.props.axisY ? this.props.axisY :0,
width:this.props.width ? this.props.width: 200,
height:this.props.height ? this.props.height: 200,
}}
onDragStop={this.onDragStop}
>
<div className={this.getCssStyle(boxType)}>
{this.show(contentObjectId)}
</div>
</ResizableAndMovable>
</div>
);
}
}
But I want to show the position x,y
How can I get the this.resizableandmovable.state in father component ?
**father component **
import DragAndResizeBox from './DragAndResizeBox';
boxes.map(box => {
return (
<DragAndResizeBox key={box.id} />
);
});
// Can I directly access this.resizableandmovable.state ???
//<div>X:<textarea>{this.resizableandmovable.state.x}</textarea>Y:{this.resizableandmovable.state.y}<textarea></textarea>
Short answer is no you can't.
What you can and should do is to store state in the parent component. And pass down to child component via props.
Updating function also normally sits inside parent component and passed down as props to the child.

Resources