Context lost in parent component when called from child - reactjs

I've got a parent component which feeds a onSomeAction prop to a child component:
export default class myComponent extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="mycomponent">
<ChildComponent onSomeAction={this.doSomething} />
</div>
)
}
doSomething() {
console.log(this);
}
}
In the child component when something is clicked on I'm calling a method whiih in turns calls the onSomeAction prop:
export default class ChildComponent extends Component {
render() {
return (
<div className="">
<a onClick={() => this.doIt()}>doIt</a>
</div>
)
}
doIt() {
const { onSomeAction } = this.props;
onSomeAction();
}
}
The problem I'm seeing is back in the parent component the this context seems to have been lost - the console.log in the doSomething method returns undefined. Why is this? I need to be able to access
the parent component context.

You need set context in parent component, you can do it with .bind
<ChildComponent onSomeAction={ this.doSomething.bind(this) } />
^^^^^^^^^^^^
Example

There are two options for you on how you can get the element that has been clicked or the whole component scope this.
option one:
instead of logging this you should logg the event target like so:
doSomething(e) {
console.log(e.target);
}
option two:
you have to attach the this keyword to the doSomething method like so:
constructor(props) {
super(props);
this.doSomething = this.doSomething.bind(this);
}
That was you'll be able to access the keyword this in your do something method.
Option3:
If you want to refer with this to the child component then you have to bind(this) on the function call int he child component

Actually you can fix it 3 ways:
<ChildComponent onSomeAction={ this.doSomething.bind(this) } />
<ChildComponent onSomeAction={ () => this.doSomething() } />
<ChildComponent onSomeAction={this.doSomething} />
and add this to constructor: this.doSomething = this.doSomething.bind(this)

Related

Trigger a function that is inside the child component from the parent

How can I trigger a function that is inside the child component from the parent component doing it in the same style as drawer navigation.
They do it like this: this.props.navigation.toggleDrawer(); from the parent
How can I do the same?
If I understood your question correctly, I think you mixed up thing a bit. The example you are showing is an example for triggering a parent component's function from child.
I'll try to clear things up a bit with 2 examples.
1) Trigger from child:
To trigger a function of a parent component from a child you can just pass the function as a property to the child component and run it when you need it.
class Parent extends React.Component {
someFunction = (text) => {
console.log('Message from child: ', text);
}
render () {
return(
<Child someProperty={this.someFunction} />
)
}
}
class Child extends React.Component {
_onPress = () => {
// check if the property is defined and not null
if(this.props.someProperty) {
// run the function that is passed from the parent
this.props.someProperty();
}
}
render() {
return(
<Button onPress={this._onPress} title="Click Me"/>
)
}
}
2) Trigger from parent:
To trigger a function on a child component from parent, you can pass a property that changes when some action happens on the parent component. This will trigger a re-render (in most cases, for more info please take a look at shouldComponentUpdate) in child component. You can check the property changes and then do what you need to do in child component.
class Parent extends React.Component {
state = {
someParameter: 'someInitialValue',
}
someFunction = (text) => {
this.setState({ someParameter: 'someValue' });
}
render () {
return(
<Child someProperty={this.state.someParameter} />
)
}
}
class Child extends React.Component {
someFunction = (text) => {
console.log('Message from parent: ', text);
}
componentDidUpdate(prevProps, prevState, snapshot) {
// Check if the suplied props is changed
if(prevProps.someProperty !== this.props.someProperty) {
// run the function with the suplied new property
this.someFunction(this.props.someProperty);
}
}
render() {
return(
{/* ... */}
)
}
}
Since you haven't provided any code. Here are my thoughts on the problem.
When you list down a component in a navigator, be it StackNavigator or DrawerNavigator, the component will receive some props provided by the navigation class itself.
There's an option to send more parameters as props to these navigation objects. Among these extra parameters, can be your one method toggleDrawer().
Also, if you parent component is listed in the navigator and the child component is not. You'll need to explicitly pass the navigation props (this.props.navigation) to the child component.
So, when you are inside that child component, all you gotta do is fetch those props and voila, it'll do the needful!
Hope this clarifies out stuff for you.
EDIT --- For your third comment
Assumptions:
Parent component is listed as DrawerNavigator({ParentScreen: {screen: ParentScreen}})
There is a <Route/> component in ParentScreen.
So, what you can do is pass the default navigation props to the <Route> component.
Like - <Route navigation={this.props.navigation} /> and in child component, you can trigger this.props.navigation.toggleDrawer() on any onPress() event of any element.
class Parent extends React.Component {
parentFunction() {
this.refs.chid.childFunction(parameterToPassed);
}
render () {
return(
{/* ... */}
<Child ref='child' />
{/* ... */}
)
}
}
class Child extends React.Component {
childFunction(text){
console.log('parameter Passed from parent: ', text);
}
render() {
return(
{/* ... */}
)
}
}
Function named as childFunction is declared in child component. and called in parent component, inside the function parentFunction.
for more information Call child function from parent component in React Native

How to update parent state from child component in React + send a paramater

I am following this tutorial but it does not say how to pass to the function a parameter.
In they the child they have
<Button onClick={this.props.action} />
handler(id) {
this.setState({
messageShown: true,
id : id
});
}
what happens if I want to send a value along with it(say some id or something).
I tried to do
<Button onClick={() => this.props.action(1)} />
but then my "state" is undefined.
It's hard to say what's going wrong without seeing a full code example, but what you're trying to do is certainly possible. Here's a working example.
class Parent extends React.Component {
constructor(props) {
super(props)
// Bind the this context to the handler function
this.handler = this.handler.bind(this);
// Set some state
this.state = {
messageShown: false
};
}
// This method will be sent to the child component
handler(id) {
this.setState({
messageShown: true,
id: id
});
}
// Render the child component and set the action property with the handler as value
render() {
console.log(this.state);
return (
<div>
<Child action={this.handler} />
<div>{this.state.id}</div>
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
{/* The button will execute the handler function set by the parent component */}
<button onClick={() => this.props.action(1)} > button </button>
</div>
)
}
}
ReactDOM.render(<Parent />, document.getElementById('main'));
<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="main"></div>
To achieve what you want, in your Child component you should call a function that calls passed function. In this case you’ll be able to pass any parameter you want.
Let’s code!
Your Parent component will be:
class Parent extends React.Component {
constructor(props) {
super(props)
// Bind the this context to the handler function
this.handler = this.handler.bind(this);
// Set some state
this.state = {
messageShown: false,
id: -1 // initialize new state property with a value
};
}
// This method will be sent to the child component
handler(id) {
this.setState({
messageShown: true,
id: id
});
}
// Render the child component and set the action property with the handler as value
render() {
return <Child action={this.handler} />
}
}
And your Child component will be
class Child extends React.Component {
render() {
return (
<div>
{/* The button will execute the handler function set by the parent component, passing any parameter */}
<Button onClick={() => this.props.action(1)} />
</div>
)
}
}
Hope this helps
Usually when this.state is undefined after invoking a callback function it is a binding issue. Double check that the handler function has this bound to it in the parent component's constructor.
this.handler = this.handler.bind(this);
More on binding: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

componentWillReceiveProps not firing even props value updated

There is simple scenario I updated a value in parent which passed to child component and expected cWRP method firing but not. here code below;
Parent component:
class App extends Component {
changeProps(){//interpreter jumps here fine..
debugger
this.appState.index=15 //update props value
}
render() {
return (
<div className="App">
<EasyABC parentUpdateProps={this.changeProps} appState={this.props.appState} />
</div>
)
}
}
child component:
#observer
export default class EasyABC extends Component{
constructor(props){
super(props)
}
componentWillReceiveProps(nextProps){//why its not jump here after update props in parent?
debugger
}
playSound(){// when this method called, cWRP above should be invoked rigth?
this.props.parentUpdateProps()
}
render(){
return(
<div>
<a onClick={()=> this.playSound()}>Play Sound Again</a>
Edited: i am using mobx as state handler, but dont bother with it
You need to update the state of the component using setState and use the same for passing it to child component
class App extends Component {
constructor() {
this.state = {
index: 0,
};
this.changeProps = this.changeProps.bind(this);
}
changeProps(){
this.setState({
index: 15,
});
// this will update state (not props)
}
render() {
return (
<div className="App">
<EasyABC
parentUpdateProps={this.changeProps}
appState={...this.state}
/>
</div>
);
}
}
<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>
You are updating the state wrongly. You have to use setState e.g.
changeProps() {
this.setState({
index: 15
});
}
You have to dereference the observable value in the render function or it will not fire the will receive props because the component is not actually using it to render.
You could just do something like this:
render() {
if (this.props.appState.index) {
return <div>Play Sound Again</div>;
}
return <div>Play Sound</div>;
}
It really doesn't matter how you use it, but that you access it within the call stack of the render method.

How to send or update data as state or prop to app.jsx from child component

I am new in react js.
I need to change the whole view on click of button
For this i need to update parent component's state from child component.
Like we do as a session variable. Do you guys have any idea about it then please help me out.
Thanks in advance.
This is my code :
App.jsx
class App extends React.Component {
constructor(props) {
super(props)
}
render() {
let RedirectTo = this.state.page;
let RenderPage;
switch (RedirectTo) {
case 'component':
RenderPage = true && <NextPage />;
break;
default:
RenderPage = true && <Index />;
}
return (
<div>
{RenderPage}
</div>
);
}
Child.jsx
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {redirect: 'yes'};
this.state = {page: 'component'};
}
render() {
if (this.state.redirect === 'yes') {
return (
<div>
{ true && <App /> }
</div>
);
} else {
return (
<div>
<a onClick={this.Validate} href="javascript:void(0);">
Click To Next
</a>
</div>
);
}
}
First, React component working on Parent to child manner not child to parent, whatever function you want to call which can affect your parent from child then you have to pass the props into child and invocation happen through the parent so that will affect your parent as well as child,
What you want to tried to achieve is wrong way you have to introduce the Router in your application which can route the one page to another one you need to check the React-Router for that so basically navigation of one component to another component we can easily achieve using react-router, React-Router
Just make a function in parent like
function () {
// your functionality here
}
then call the child component in parent as
<child functionProp = {this.function} />
In your child component call the function in parent by
this.props.functionProp
In parent you can pass a function as props to the child as:
<child someFunction={this.handleFunction} />
And in handleFunction method in parent you can do whatever you want.
handleFunction(value) {
//do something
}
And in child you can call that someFunction as:
this.props.someFunction(value)
In this way you can communicate to parent through child.

React - How to pass `ref` from child to parent component?

I have a parent and a child component, I want to access the ref of an element which is in the child component, in my parent component. Can I pass it with props?
// Child Component (Dumb):
export default props =>
<input type='number' ref='element' />
// Parent Component (Smart):
class Parent extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
const node = this.refs.element; // undefined
}
render() {
return <Dumb { ...this.props }/>
}
}
You could use the callback syntax for refs:
// Dumb:
export default props =>
<input type='number' ref={props.setRef} />
// Smart:
class Parent extends Component {
constructor(props) {
super(props);
}
setRef(ref) {
this.inputRef = ref;
}
render(){
return <Dumb {...this.props} setRef={this.setRef} />
}
}
With react^16.0.0 you would use React.createRef(). Using #Timo's answer, it would look like this:
// Dumb:
export default props =>
<input type='number' ref={props.setRef} />
// Smart:
class Parent extends Component {
constructor(props) {
super(props);
this.ref1 = React.createRef()
}
render(){
return <Dumb {...this.props} setRef={this.ref1} />
}
}
As per DOC:
You may not use the ref attribute on functional components because
they don't have instances. You should convert the component to a class
if you need a ref to it, just like you do when you need lifecycle
methods or state.
So i think, if you want to use the ref, you need to use class.
Check this: https://github.com/facebook/react/issues/4936
If you need dynamic refs, because you have an array or something, like I did. Here is what I came up with after reading the answers above.
Also this assumes the myList is an array of objects with a key property. Anyways you get it.
Also this solution works without any issues from TypeScript as well.
const Child = props => <input ref={refElem => setRef(props.someKey, refElem)} />
class Parent extends Component {
setRef = (key, ref) => {
this[key] = ref; // Once this function fires, I know about my child :)
};
render(){
return (
{myList.map(listItem => <Child someKey={listItem.key} setRef={this.setRef} />)}
)
}
}
Anyways hope this helps someone.

Resources