Accessing/Changing Parents State from Child Class using props (React) - reactjs

I am trying to set state of the parent class with the child. But having trouble figuring out how to do this. I've abstracted away anything I deemed irrelevant to the question at hand. The issue is that I am
Class Parent extends Component {
constructor(props){
super(props)
this.state = {
foo: "bar"
}
}
coolMethod(n){
this.setState({foo: n})
}
render{
return(
<Child coolmethod={this.coolMethod} />
)
}
}
Class Child extends Component {
constructor(props){
super(props)
}
componentDidMount(){
let that = this;
videojs('my-player', options, function onPlayerReady() {
this.on('end',()=>{
that.props.coolMethod(<whatever string returns as a result of
this method>)
})
})
}
render{
return(
// irrelevant stuff to this question
)
}
}
Currently this code gives me "type error: this.setState is not a function"
If you want more info on videojs: http://videojs.com/ (though this is irrelevant to the question by itself, other than the fact that I reference it in my videojs call in componentDidMount of the child)

I assume the 2nd class is Class Child extends Component .... You need to bind this.coolMethod in your Parent constructor first.
Class Parent extends Component {
constructor(props){
super(props)
this.state = {
foo: "bar"
}
this.coolMethod = this.coolMethod.bind(this);
}
coolMethod(n){
this.setState({foo: n})
}
render{
return(
<Child coolmethod={this.coolMethod} />
)
}
}

Try this, tested working on my side, found two issues in the code
Javascript is case sensitive coolmethod is passed in to the Child, but you are trying to access coolMethod.
You need this > this.coolMethod = this.props.coolMethod.bind(this); in the constructor to inherit the setState function from the Parent, otherwise, this inside the coolMethod will be undefined.
import React, { Component } from 'react';
export default class Parent extends Component {
constructor(props){
super(props)
this.state = {
foo: "bar"
}
}
coolMethod(n){
this.setState({foo: n})
}
render(){
return(
<Child coolMethod={this.coolMethod} />
)
}
}
class Child extends Component {
constructor(props){
super(props)
this.coolMethod = this.props.coolMethod.bind(this);
}
render(){
return(
<button onClick={() => this.coolMethod("aabbcc")}>1</button>
)
}
}

Related

React. How to call method of specific subchild in component tree

I'm starting to learn React and wonder how the following theoretical problem can be solved.
Suppose I have such components.
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
galaxyData:{}
};
}
handleGalaxyCommand(cmd) {
...
}
render() {
return (
<Galaxy galaxyData={this.state.galaxyData} />
);
}
}
class Galaxy extends React.Component {
render() {
return (this.props.galaxyData.sectors.map((sector) =>
<Sector sectorData={sector.sectorData} />
)
);
}
}
class Sector extends React.Component {
render() {
return (this.props.sectorData.ships.map((ship) =>
<Ship shipData={ship.shipData} />
)
);
}
}
class Ship extends React.Component {
constructor(props) {
super(props);
this.state = {
x: this.props.shipData.inialX,
y: this.props.shipData.inialY,
};
}
moveTo(x,y){
...
}
render() {
return <div x={this.state.x} y={this.state.y} id={this.props.shipData.id}/>
}
}
I wrote the code quickly for an example only, so I apologize for any syntax errors.
So the component tree looks something like this.
<Galaxy>
<Sector>
<Ship/>
...
<Ship/>
</Sector>
<Sector>
<Ship/>
...
<Ship/>
</Sector>
</Galaxy>
There may even be thousands of ships.
The ship has a "moveTo" method, which starts the Timer to change the x and y variables in the state, which causes the re-render, the move effect.
Let's assume that the Game component receives the command via the "handleGalaxyCommand" method to make the ship start moving.
How to call the "moveTo" method on a ship that interests me?
This is actually possible in react :) in a very simple way.
But this works only in class-based components (not functional or hooks).
Basically, you can call any child's methods from the parent if you access it's refs
Something like:
class Parent extends Component {
childRef = null;
componentDidMount() {
//via ref you can call it
this.childRef.myCustomMethod();
}
render() {
return <Child ref={ref => this.childRef = ref} />
}
}
class Child extends Component {
myCustomMethod() {
console.log("call me ");
}
render() {
return <div />;
}
}
Check this part of the docs for more details: https://reactjs.org/docs/refs-and-the-dom.html#adding-a-ref-to-a-class-component

Reactjs: Parent function call triggered by a child

So I am building my first react project and stumbled upon following problem:
In my App.js (main application) I got a function and render my components:
class App extends Component {
constructor(props) {
super(props);
this.candidateCounter = 0;
this.setCandidateVote = this.setCandidateVote.bind(this);
}
...
setCounter (name) {
this.candidateCounter++;
console.log(this.candidateCounter);
}
render() {
...
<Candidates setCounter={this.setCounter} />
}
}
The child component Candidates.jsx has another function and thus calls another component:
export class Candidates extends React.Component {
constructor(props) {
super(props);
this.AppProps = props;
}
...
registerVote(name) {
...
this.AppProps.setCounter(name);
}
render() {
...
<MyButton id={this.state.candidates[i].name} register={this.registerVote} />
}
And the last component MyButton.jsx looks like this:
export class MyButton extends React.Component {
constructor(props) {
super();
this.ParentProps = props;
this.state = { active: false }
}
buttonActiveHandler = () => {
this.setState({
active: !this.state.active
});
if (this.state.active === false) {
this.ParentProps.register(this.ParentProps.id);
}
else {
...
}
}
render() {
return (
<Button content='Click here' toggle active={this.state.active} onClick={this.buttonActiveHandler} />
);
}
}
I have successfully debugged that all functions calls are working except when the grandchild MyButton has triggered the registerVote() function in my Candidates module. Logging in this method gets printed but it cannot call this.AppProps.setCounter() from the parent App. I receive the following error:
TypeError: Cannot read property 'setCounter' of undefined
I hope this wasn't too complicated explained, any help is appreciated :)
Simply bind the function in the constructor of the class as #qasimalbaqali stated in his comment.
constructor(props) {
super();
this.registerVote = this.registerVote.bind(this);
}

Update a react components state from its parent

Is it ok to update React components state by calling its member function from its parent. Something like:
class SomeComp extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
updateState(data) {
this.setState({ data: data })
}
render() {
return (<div>this.state.data</div>);
}
}
Is it ok to update React components state by calling its member function from controller?
Yes, you can do that but it's unnecessary. Usually you want to update the child state by passing down props from the parent. I've made some examples of how you can update a Child from the Parent below.
Example 1:
In this example, you don't need any state for the Child. The Parent manages the state and passes down any changes to the Child via props. This is the recommended approach.
Parent
class Parent extends React.Component {
constructor() {
super();
this.state = {text: "hello"};
}
render() {
return <Child data={this.state.text} />;
}
}
Child
class Child extends React.Component {
render() {
return <span>{this.props.data}</span>;
}
}
Example 2:
In this example, we use two states, one for each component. This is unnecessary for this implementation, but you can still do it. When the Child mounts, we set the state to whatever the data prop is set to. We update the state whenever the Child component receives props with componentWillReceiveProps().
Parent
class Parent extends React.Component {
constructor() {
super();
this.state = {text: "hello"};
}
render() {
return <Child data={this.state.text} />;
}
}
Child
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {childText: props.data};
}
componentWillReceiveProps(nextProps) {
if(nextProps.data !== this.props.data)
this.setState({childText: data});
}
render() {
return <span>{this.state.childText}</span>;
}
}
Example 3:
In this example, the Child component is given a ref which we then can use to trigger a Child function from Parent. Usually this is done in the reverse order (triggering a function from Child to Parent), but you can still do this if you want. This is the more manual approach and similar to what you asked.
Parent
class Parent extends React.Component {
constructor() {
super();
this.state = {text: "hello"};
}
triggerUpdate = () => {
this.child.component.update(this.state.text);
}
render() {
return <Child ref={(el) => this.child = el} data={this.state.text} />;
}
}
Child
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {childText: props.data};
}
update = (text) => {
this.state({childText: text});
}
render() {
return <span>{this.state.childText}</span>;
}
}

Changing the state of a parent component using a function in the child compontent

I'm new to React, and I decided to build something simple like a Calculator to practice it's basics. However I have some trouble to understand the logic behind the information flow, and either there is a way for a child component to do the logic and update the parent in a natural way.
For example this is the basic structure of my calculator:
class Calculator extends React.Component {
render() {
return (
<div className="calculator-main">
<Screen numberOnScreen={this.state.numberOnScreen}/>
<NumberButton number={7} />
<NumberButton number={8} />
<NumberButton number={9} />
<OperatorButton operator="plus" view="-"/>
....
</div>
)
}
}
class Screen extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="screen">{new Intl.NumberFormat().format(this.props.numberOnScreen)}</div>
);
}
};
class NumberButton extends React.Component {
constructor(props) {
super(props);
}
render() {
const zeroClass = this.props.number === 0 ? " zero" : "";
return (
<button type="button" className={"number" + zeroClass}>{this.props.number}</button>
);
}
};
So I know that:
I can create the functions inside Calculator and pass it as a prop to
the buttons components, and call it onClick. (But it just feel weird).
Create an event listener in the Calculator compontent, create the
function inside the button component and pass the value via the event
trigger; (But it feels artificial).
Use some kind of global store?
But is there no natural react way to do this?
Thanks!
I think you want to know about React component communication. Here, I have implemented Child to Parent communication.
In this case Parent's state and state change method passes to child component through props. Then child can change parent's state use this method.
React Component Communication
//Parent component
class Parent extends React.Component{
constructor(props){
super(props);
this.state = {
content: 'Initial Content'
}
this.changeContent = this.changeContent.bind(this);
}
changeContent(event){
this.setState({
content: event.target.value
})
}
render(){
let { content } = this.state;
return <div>
<Child content={content} changeContent={this.changeContent}/>
<h1>{content}</h1>
</div>
}
}
// Child component
class Child extends React.Component{
constructor(props){
super(props);
}
render(){
let { content, changeContent } = this.props;
return <input value={content} onChange={changeContent}/>
}
}

How do I pass parent state to its child components?

I am new in React ES6 and I think I am modifying the state in a wrong way. My code is like this when I set state on parent component:
class App extends React.Component {
constuctor(props) {
super(props);
this.state = {name:"helloworld"};
}
render() {
return(
<ChildComponent parentObj={this} /> // parentObj for parent context as props on child components
);
}
}
My problem is in other child components, I have to do it repeatitively, is there another way of doing it? I have no problem with React.createClass, but I want to code in es6 so i have this problem.
If you wanna pass the state {name:"helloworld"} do it like that:
class App extends React.Component {
constuctor(props) {
super(props);
this.state = {name:"helloworld"};
}
render() {
return(
<ChildComponent {...this.state} />
);
}
}
and in the child component you can do:
<Text>{this.props.name}</Text>
But If you want to pass the props of the component to it's child:
class App extends React.Component {
constuctor(props) {
super(props);
this.state = {name:"helloworld"};
}
render() {
return(
<ChildComponent {...this.props} />
);
}
}
and in the child component you can do:
<Text>{this.props.stuff}</Text>//place stuff by any property name in props
Now if you want to update the state of parent component from the child component you will need to pass a function to the child component:
class App extends React.Component {
constuctor(props) {
super(props);
this.state = {name:"helloworld"};
}
update(name){
this.setState({name:name})// or with es6 this.setState({name})
}
render() {
return(
<ChildComponent {...this.props, update: this.update.bind(this)} />
);
}
}
and then in child component you can use this : this.props.update('new name')
UPDATE
use more es6 and removed constructor
class App extends React.Component {
state = {name:"helloworld"};
// es6 function, will be bind with adding .bind(this)
update = name => {
this.setState({name:name})// or with es6 this.setState({name})
}
render() {
// notice that we removed .bind(this) from the update
return(
//send multiple methods using ','
<ChildComponent {...this.props, update = this.update} />
);
}
}
if you want to send the whole state :
return( <ChildComponent {...this.state} /> );
But this is likely a bad idea :)
edit: in your scenario, this sends a 'name' property to child component with value 'helloworld'

Resources