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
Related
I have a Parent component that contains a Child component. Suppose that the Parent wants to ask the Child its preferred background color and uses it to modify how the Parent renders itself:
class Child extends React.Component {
favoriteColor = () => "red";
render = () => (<span>Hello world</span>);
}
class Parent extends React.Component {
render = () => {
const child = (<Child />);
return (
<div style={{backgroundColor: child.favoriteColor()}}>
{child}
</div>
);
};
}
What is the idiomatic way to do this in React?
In my real project, I have a Parent component that has a dynamic set of children. The Parent wraps each child in a React Bootstrap <Col>. But sometimes a child does not want to be rendered, and the correct thing would be to omit the <Col>. So the Parent component needs to be able to ask each child "do you have anything to render?"
One way to do this depending on the circumstances is to declare Child.favoriteColor as static. As a static function it has no access to the instance's props or state.
class Child extends React.Component {
static favoriteColor = () => "red";
render = () => (<span>Hello world</span>);
}
class Parent extends React.Component {
render = () => {
return (
<div style={{backgroundColor: Child.favoriteColor()}}>
<Child />
</div>
);
};
}
say i have this React Class. This is NOT my main component that I'm rendering. how can i pass the state i set in here UPWARDS to the parent component.
class Player extends React.Component {
constructor(props) {
super(props);
this.state = {
playerOneName: ''
}
this.selectPlayerOne = this.selectPlayerOne.bind(this);
}
selectPlayerOne(e, data) {
this.setState({playerOneName: data.value})
}
render() {
let players = [];
this.props.players.map((player) => {
players.push({text: player.name, value: player.name})
})
return (
<div className="playersContainer">
<div className="players">
<Dropdown onChange={this.selectPlayerOne} placeholder='Select Player One' fluid selection options={players} />
</div>
</div>
)
}
}
when I say parent component i mean the class that is going to display player like so:
<Player />
I.e. how can I make this.state.playerOneName available to the parent?
Hey so the point here is that you are basically passing in, from your parent component into your child component, a prop which is a function.
In parent:
handler(newValue){
this.setState({key: newValue})
}
render() {
return(
<Child propName={handler.bind(this)}>
)
}
When a change takes place in your child component, you call the function and pass in the new value as an input. This way you are calling the function in your child component, and making a change to the state of the parent component.
In your case you want to, instead of setting the state of playerOneName, pass in a function from the parent of this class and do something like this.props.functionFromParent(playerOneName) in your 'selectPlayOne' function.
It is true that the flux pattern is unidirectional, however when you're dealing with smart and dumb components you will see that data is passed from a dumb component to a smart component in this way. It is perfectly acceptable React form!
"Lifting state up" for React means that you should replace data from your child component to parent component state and pass data for presentation to child component by props.
You can do something like this to achieve your goal. Create a parent component which hold playerOneName as its state. Pass it as a prop to child component and with that also a function that changes the playerOneName whenever it is changed in the child component.
class Parent extends Component {
constructor(props){
this.state = {
playerOneName: ''
}
}
render() {
return(
<Child
playerOneName={this.state.playerOneName}
onPlayerOneNameChange={(playerOneName) => this.setState({playerOneName})}
/>
);
}
}
Use this function like this in child component to change the name of playerOneName in Parent component, like this your child component is only displaying the value of the playerOneName all the changes are done in Parent component only.
class Child = props => {
const { playerOneName, onPlayerOneNameChange } = props;
return (
<TextInput
value={playerOneName}
onChangeText={(playerOneName) => onPlayerOneNameChange(playerOneName)}
/>
);
}
By this you can use updated playerOneName in your Parent component whenever you like by using this.state.playerOneName
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.
How can I add an onScroll listener in a component to catch a scroll of a parent element?
class ChildDiv extends React.Component {
constructor() {
super();
}
handleScrollOfParent() {
// do stuff when parent <main> scrolls;
}
render() {
return (
<div id="child" onScroll={this.handleScrollOfParent.bind(this)}>
// content with overflow: hidden and scroll handled by parent MAIN.
</div>
)
}
}
export default ChildDiv;
Rendered in a parent main, like this <main><ChildDiv /></main> and I want to catch the scroll of the main.
You could either:
1) try to grab the parent node from the child component:
componentDidMount() {
ReactDOM.findDOMNode(this).parentNode.addEventListener(...
}
2) pass the parent node as props and attach listener after rendered:
In parent:
render{
return(
<div className="parent" ref={(elem)=>{this.node=elem}}>
<Child parentNode={this.node}/>
</div>
)
}
and in child (parentNode is still undefined in constructor, check in next props):
componentWillReceiveProps(newProps){
newProps.parentNode.addEventListener(...
}
According to React's nature, which is passing props from Parent down to Children, so when you want the Child element to update its parent, you need to create a function on Parent, and pass to the Child as props
Please also refer to my answer to a similar issue (how to trigger the parent component to do something from the child/grandchild/or great-grandchild):
Re-initializing class on redirect
In your case, we may do something like this:
1/ Create a function on Parent that trigger the Parent itself to do something:
import React from 'react';
class Parent extends React.Component {
constructor(props) {
super(props);
// ...
}
doSomeThingOnParent = () => {
// do whatever you want with this Parent component, setState, forceUpdate etc.
}
render(){
// ...
<Child doSomeThingOnParent={this.doSomeThingOnParent} />
// ...
}
}
2/ On Child Component, trigger the above function using onScroll:
class Child extends React.Component {
...
render() {
return (
<div id="child" onScroll={this.props.doSomeThingOnParent}>
// your content
</div>
)
}
}
However, you cannot render the Parent by your mentioned way, which is:
You should use like the Parent's render method above, and also set the CSS to allow overflow for your Child component
You could define a state variable in the parent component that would store the current scrollTop value (assuming vertical scrolling) and update in every time the scroll event happens and then pass this variable to the ChildDiv which could detect that the variable has changed in componentWillReceiveProps:
if(this.props.yourVariable != nextProps.yourVariable){
// scroll event was fired => scroll position changed
}
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)