I have react component which returns an integer. Structure of the class component is as follows:
class MyClass extends Component {
constructor(props) {
super(props);
this.state = {
variable : 0
}
}
componentDidMount(){
// do some works
this.setSate({variable:$someValue});
}
render(){
var temp = this.state.variable;
return temp;
}
}
I need to fetch the value returned from MyClass in another class component in React within render.
If I call like,
render () {
return (
<div>{Myclass}</div>
);
}
it works fine. is there any way to call this outside return, and assign the value to a variable?
Try utilizing 'this.props' instead. You can pass in something like this
class MyClass extends Component {
constructor(props) {
super(props);
this.state = {
variable : 0
}
}
componentDidMount(){
// do some works
this.setSate({variable:$someValue});
}
render(){
const {variable} = this.state
return (
<MyOtherClass variable = {variable}/>
);
}
}
And in MyOtherClass:
render() {
const {variable} = this.props
return (
<div>{variable}</div>
);
}
You should be able to extend MyClass and call super.render()
class MyOtherClass extends MyClass {
render() {
const value = super.render();
return (
<div>{value}</div>
);
}
}
edit: working example in codesandbox.io
Related
Let's have components A and B.
Component B only shows the parent's state in contentForB in a different format and doesn't manipulate with it. It takes A's state as a prop, applies a function transform(content) and shows it, so whenever A's contentForB changes, the new content get transformed and updated in B.
The problem comes when A wants to use B's transformed content and use it somewhere else. I tried to implemented in a standard way, using state-updating function and passed it from A to B like this:
class A extends React.Component {
constructor(props) {
super(props);
this.state = {
contentForB: "",
transformedContent: ""
};
this.updateTransformedContent = this.updateTransformedContent.bind(this);
}
updateTransformedContent(newContent) {
this.setState = { transformedContent: newContent };
}
render() {
return (
...
<B content={ this.state.contentForB }
updateTransformedContent={ this.updateTransformedContent } />
<ComponentUsingTransformedContent transformedContent = { this.state.transformedContent } />
);
}
}
class B extends React.Component {
constructor(props) {
super(props);
this.transform = this.transform.bind(this);
}
transform(content) {
let newContent = ...;
this.props.updateTransformedContent(newContent);
return newContent;
}
render() {
<Something value={this.transform(this.props.content)} />
}
}
However, when A's state changes, B gets reinitialized, it then changes A's state by calling the updateTransformedContent which again causes B to get reinitialized, thus causing an infinite loop even though the updateTransformedContent changes the state object which isn't directly passed into B.
Any ideas how to deal with such situation properly?
You can use componentDidUpdate lifecycle method.
[codesandbox.io]
https://codesandbox.io/s/cool-leaf-92nt8?file=/src/App.js:457-475
class TestB extends Component {
constructor(props) {
super(props);
this.state = {
transformed: ""
};
this.transform = this.transform.bind(this);
}
componentDidUpdate(prevProps) {
if (this.props.content !== prevProps.content) {
this.transform(this.props.content);
}
}
transform(content) {
const transformed = `<h4>${this.props.content}</h4>`;
this.setState({ transformed: transformed });
this.props.updateTransformedContent(transformed);
return transformed;
}
render() {
return (
<div>
<h4>B Componenet:</h4>
<p>{this.state.transformed}</p>
</div>
);
}
}
I want to update the value of 'change_color' in the second class and automatically render it in the first class when the value gets changed.
Assume, 'Second' component as the child of the 'First' component.
Solved it. Code is edited and it is the answer.
class First extends Component {
constructor() {
super();
this.state = {
change_color: false
}
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
this.setState({
change_color: true
})
}
render() {
console.log(this.state.change_color);
return(<div><Second colorChange={this.handleChange} /></div>)
}
}
class Second extends Component {
constructor() {
super();
}
render() {
return(<div><button onClick={this.props.colorChange} /></div>)
}
}
Maybe you can try this, just make a container component, and set the value you want to change into a state of the container component, add a method to change the state value, then, you can use "this.props.handleColorChange" to call the method of the parent component in children components.
class ParentComponent extends Component {
constructor() {
super();
this.state = {
change_color: false
}
}
handleColorChange= () => {
const {change_color} = this.state;
this.setState = {
change_color: !change_color
}
}
render() {
const {change_color} = this.state,
{handleColorChange} = this;
return (
<div>
<ChildComponent1
color={change_color}
handleColorChange={handleColorChange}
/>
<ChildComponent2
color={change_color}
handleColorChange={handleColorChange}
/>
</div>
);
}
}
class ChildComponent1 extends Component {
constructor() {
super();
}
render() {
const {color} = this.props;
return(
<span>now, the color is {color}</span>
)
}
}
class ChildComponent2 extends Component {
constructor() {
super();
}
const {handleColorChange} = this.props;
return(
<button onClick={handleColorChange}>click to change color</button>
)
}
What you need to do is lifting up the state. Create a new component that has a state with the colour and the change colour function. Then pass to first and second componentes the corresponding properties as props and inside of them call the function to change the colour. Does it makes sense?
I'm probably asking the wrong question, but I'd like to be able to execute a parent function when called from a child function, not an event.
I have more or the less the following setup: Declaring the _foo method in the parent and passing it on down to ChildTwo, where executing it via an onClick event handler works as expected. However, I ran into a situation where I need to call the _foo method manually from inside another method (I've simplified it here, but it will be called conditionally).
My question is what do I need to do to call the _foo method from _bar() ?
Thanks in advance!
export defaultclass Parent extends Component {
constructor() {
super();
}
_foo() {
alert('alert!');
}
render() { <ChildOne _foo={this._foo.bind(this)} /> }
}
const ChildOne = (props) => {
const { _foo } = props;
return ( <ChildTwo _foo={_foo} /> );
}
export default class ChildTwo extends Component {
constructor(props) {
super(props);
this._foo = this.props._foo.bind(this);
}
_bar() {
//this._foo.call();
//this._foo();
//what do I do here?
}
render() {
return (
<div>
<button onClick={this._foo}> Works! </button>
<button onClick={this._bar}>Doesnt Work!</button>
</div>
);
}
};
If you really want to do this, then I would solve it by passing the child component as an argument to the method that is still bound to the original parent.
For example:
export defaultclass Parent extends Component {
constructor() {
super();
this._foo = this._foo.bind(this)
}
_foo(childComponent) {
alert({ parent: this, child: childComponent });
}
render() { <ChildOne _foo={this._foo} /> }
}
const ChildOne = (props) => {
const { _foo } = props;
return ( <ChildTwo _foo={_foo} /> );
}
export default class ChildTwo extends Component {
constructor(props) {
super(props);
this._bar = this._bar.bind(this);
}
_bar() {
const { _foo } = this.props;
// Passing a reference to self as argument
_foo(this);
}
render() {
return (
<div>
<button onClick={this._bar}>Should Work Now!</button>
</div>
);
}
};
I am trying to convert my React classes to ES6, but I am having some difficulty within this process.. I would like to have my bindings in the constructor, not in the render view.
Now, if I have a root module with a setState which needs a parameter, e.g.:
constructor() {
super();
this.state = {
mood: ""
};
this.updateMood(value) = this.updateMood.bind(this,value);
}
updateMood(value) {
this.setState({mood: value});
}
Then I pass this function to a component:
<customElement updateMood={this.updateMood}></customElement>
Then within the customElement module, I have something like this:
constructor() {
super();
}
update(e) {
this.props.updateMood(e.target.value);
}
and in the render:
<input onChange={this.update} />
Is this the correct way? Since I can't get it to work ;-(
You can't use this this.updateMood(value) = this.updateMood.bind(this,value); construction, because it is syntax error.
You can solve your problem like this
class CustomElement extends React.Component {
constructor() {
super();
this.update = this.update.bind(this);
}
update(e) {
this.props.updateMood(e.target.value);
}
render() {
return <input onChange={this.update} />
}
}
class Parent extends React.Component {
constructor() {
super();
this.state = {
mood: ""
};
this.updateMood = this.updateMood.bind(this);
}
updateMood(value) {
this.setState({ mood: value });
}
render() {
return <div>
<CustomElement updateMood={this.updateMood}></CustomElement>
<h1>{ this.state.mood }</h1>
</div>
}
}
Example
Or, depending on your babel settings, or when using typescript, the following achieves the same but is a lot more convenient to write / maintain:
class Parent extends React.Component {
constructor() {
super();
this.state = {
mood: ""
};
}
updateMood = (value) => {
this.setState({ mood: value });
}
}
From what I understand, HOCs in ReactJS add props to your decorated component, but I want to add methods that can also act on the state.
As an example, I generally never call this.setState() without checking this.isMounted() first. In essence, I want:
export default ComposedComponent => class BaseComponent extends React.Component {
static displayName = "BaseComponent";
constructor(props) {
super(props);
}
//------> I want this method to be available to any ComposedComponent
//------> And it has to act upon the state of ComposedComponent
updateState(obj) {
if (this.isMounted() && obj) {
this.setState(obj);
}
}
render() {
return (
<ComposedComponent {...this.props} {...this.state} />
)
}
}
Say I want to decorate my component Home. So I'd just return it as export default BaseComponent(Home).
But this.updateState() is not available inside Home class. How do I solve this?
Okay, I figured it out. I had spent too much time on this, so I hope this answer could help somebody out as well. Short answer: add the method in your decorator to props, then bind it in your decorated class' constructor.
Here is the code:
export default ComposedComponent => class BaseComponent extends React.Component {
static displayName = "BaseComponent";
constructor(props) {
super(props);
// Note how I am adding this to state
// This will be passed as a prop to your composed component
this.state = {
updateState: this.updateState
}
}
updateState(obj) {
this.setState(obj);
}
render() {
return (
<ComposedComponent {...this.props} {...this.state} />
)
}
}
And here is an example of a class that would use it (I'm using ES7 for simplicity):
#BaseComponent
class Home extends React.Component {
static displayeName = 'Home';
constructor(props) {
super(props);
// And here I am binding to it
this.updateState = this.props.updateState.bind(this);
}
render() {
return (
<div>Hi</div>
)
}
}