How to pass variables from class to class - javascript

Alright, so I'm trying to simplify a project I'm working on, but of all the information I've read on the internet, none of it has answered my question. My doubt is how can I pass variables (the name of the variable, and its value) from one class to another class? Should I use props? Should I just do something similar to this.state.variable? How can it be done? I'll write a sample code just to show what I'm trying to do more visually, however, this is not my actual code. Thanks for helping :)
class FishInSea{
constructor(props){
super(props);
this.setState({fishInSea: 100});
}
render(){
return(
<div>Fish in the sea: {this.state.fishInSea}</div>
);
}
}
class FishInOcean{
constructor(props){
super(props);
this.setState({fishInOcean: <FishInSea this.props.fishInSea/> * 1000});
}
render(){
return(
<div>Fish in the ocean: {this.state.fishInOcean}</div>
);
}
}
export default FishInOcean;

You need to first make both the classes in to React components. Since both the classes modify the state so they called as statefull components. The class has to extend the Base class of React i.e., Component.
in constructor we only do state initialisations but won’t modify the state there. But you are modifying the state which isn’t correct. Instead move setState to componentDidMount.
Say suppose in FishInSea class you have fishInSea and you want to pass it to FishInOcean component as props.
Check below two corrected components how they are passed from one component to the other
import React, { Component } from “react”;
class FishInSea extends Component{
constructor(props){
super(props);
this.state = {
fishInSea: 100
}
}
componentDidMount(){
this.setState({fishInSea: 100});
}
render(){
const { fishInSea } = this.state;
return(
<div>Fish in the sea:
<FishInOcean fishInSea={fishInSea} />
</div>
);
}
}
import React, { Component } from “react”;
class FishInOcean extends Component{
constructor(props){
super(props);
this.state = {fishInOcean: 1000}
}
componentDidMount(){
this.setState({fishInOcean: 1000});
}
render(){
const { fishInOcean} = this.state;
const { fishInSea } = this.props;
return(
<div>Fish in the ocean: {fishInOcean}
{fishInSea}
</div>
);
}
}
export default FishInOcean;
/*There was a typo*/

Related

Share volatile variable between React Components [duplicate]

This question already has answers here:
How can I communicate between related react components?
(11 answers)
Closed 3 years ago.
I have a group of Components that render different parts of the same page. Whenever an action is commited inside one of them, the other ones should be locked (a volatile flag should be propagated through them and trigger a javascript function that disables all elements)
Block Components:
class FirstBlock extends React.Component {
constructor(props) {
super(props);
.......
}
}
render() {......}
}
class SecondBlock extends React.Component {
constructor(props) {
super(props);
.......
}
}
render() {......}
}
Page Component:
import FirstBlock from 'Components/FirstBlock';
import SecondBlock from 'Components/SecondBlock';
class PageBlock extends React.Component {
constructor(props) {
super(props);
.......
}
}
render() {
return (
<FirstBlock ... />
<SecondBlock ... />
);
}
}
Any ideas? I'm new to react and any tip will be helpful.
In (very) general terms, pass an event handler into each of your blocks from your parent. When an action is triggered from one of them, deal with this in the parent. If you need to change your behaviour depending on which child raises the action you'll need to have some kind of identifier for each of your children, so that when the handler is called it knows what to do.
class PageBlock extends React.Component {
constructor(props) {
super(props);
.......
}
}
onAction = (id)=>{
// set isVolatile or do whatever you need to do
}
render() {
return (
<FirstBlock id={firstBlockId} onAction={this.onAction}... />
<SecondBlock id={secondBlockId} onAction={this.onAction}... />
);
}
}
class FirstBlock extends React.Component {
constructor(props) {
super(props);
.......
}
}
onAction = ()=>{
this.props.onAction(this.props.id)
}
render() {......}
}
The principle is to lift your common state (i.e. that something has triggered an action) up to a parent so that the children that need to know about the state can have access to it.

this.state vs state in React

I'm working in a new codebase. Normally, I would set up state like this in a React component:
class App extends React.Component {
constructor() {
super();
this.state={
foo: 'bar'
}
}
....
In this new codebase, I'm seeing a lot of this:
class App extends React.Component {
state={
foo: 'bar'
}
....
Is there an advantage to doing it this way? They seem to only do it when state doesn't need to be altered. I always thought of state as being something React handled. Is this an ok thing to do?
The end result of both approaches is the same. Both approaches are just setting the initial state of the component. It's worth noting that class properties are a stage 3 proposal, so all development environments may not be able to use them.
I personally like to use the class field variant if nothing else is done in the constructor, as it is less code to write, and you have no super call to worry about.
Example
class Component1 extends React.Component {
state = { value: this.props.initialValue };
render() {
return <div> {this.state.value} </div>
}
}
class Component2 extends React.Component {
constructor(props) {
super(props);
this.state = { value: props.initialValue };
}
render() {
return <div> {this.state.value} </div>
}
}
function App() {
return (
<div>
<Component1 initialValue={1} />
<Component2 initialValue={2} />
</div>
);
}
Actually both of them bind to this pointer. the this that made in constructor of class.
Totally you can access to local state by this.state but in first style you can pass props to constructor by super and then use it in state declaration, just like below:
class App extends React.Component {
constructor(props) {
super(props);
this.state={
foo: 'bar',
jaz: props.someParentState,
}
}
....
Awesome, you can access to props in constructor, isn't pretty? I definitely use this style for local state declaration.
Hope this helps you.

How to avoid the setState() / render() endless loop when passing data from child to parent?

I am trying to save child-data in the state of the parent, but end up with the endless loop because setState() calls render().
Error message: Maximum update depth exceeded.This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
Relatively new to React, so I can't seem to word the question when googling solutions. I know why the error is occurring, I just don't know how to get around the issue. Is there a specific method I can use that prevents re-rendering?
Here is the parent:
export class ToDoList extends React.Component {
constructor(props){
super(props);
this.state = {
data: null
}
}
myCallback = (dataFromChild) => {
this.setState({data: dataFromChild.toUpperCase()})
}
render() {
return (
<div>
<ToDoItem callbackFromParent={this.myCallback}/>
</div>
);
}
}
The child:
class ToDoItem extends React.Component {
constructor(props){
super(props);
this.state = {
listInfo: 'Doggos'
}
}
render(){
return(
<h1>{this.props.callbackFromParent(this.state.listInfo)}</h1>
);
}
}
Your code is doing exactly that, an endless loop. When your ToDoItem component renders, it calls callbackFromParent which updates the state of ToDoList, causing ToDoList to re-render, subsequently re-rendering the ToDoItem. Since ToDoItem re-renders, it calls callbackFromParent again and so on...
I'd like to ask why you are trying to render the non-value-returning function of callbackFromParent. It doesn't return anything, so it doesn't make sense why you'd want to render it inside of your <h1> tags.
There is a small problem with the code you shared, that you are calling a function from the render() rather than binding it to some event which is making it go into infinite loop...
Is this what you are trying to achieve?
class ToDoList extends React.Component {
toUpper = (dataFromChild) => {
return dataFromChild.toUpperCase();
}
render() {
return (
<div>
<ToDoItem toUpper={this.toUpper}/>
</div>
);
}
}
class ToDoItem extends React.Component {
constructor(props){
super(props);
this.state = {
listInfo: 'Doggos'
}
}
render(){
return(
<h1>{this.props.toUpper(this.state.listInfo)}</h1>
);
}
}
ReactDOM.render(<ToDoList />, document.getElementById('root'));
<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="root"></div>
You are getting an endless loop because of the following reasons:
1) You are calling the parent callback on each render.
2) You are saving the uppercased value in the parent state.
When the parent state gets updated, the child gets re-rendered, meaning that it will call the callback again, which will cause to re-render, which calls the callback again etc...
An alternative solution would be to pass the util function down to the child which can then call it once when it re-renders. Since no state in the parent is being updated, the child will not be re-rendered.
If you're trying to save data on parent but want to display it in child, try this:
Here is the parent:
export class ToDoList extends React.Component {
constructor(props){
super(props);
this.state = {
data: null
}
}
myCallback = (dataFromChild) => {
this.setState({data: dataFromChild})
}
render() {
return (
<div>
<ToDoItem callbackFromParent={this.myCallback} data={this.state.data}/>
</div>
);
}
}
The child:
class ToDoItem extends React.Component {
constructor(props){
super(props);
this.state = {
times: 0
}
// Bind Explained below
this.iBeClicked = this.iBeClicked.bind(this);
}
iBeClicked(){
this.setState({times: ++this.props.data});
this.props.callbackFromParent(this.props.data++);
}
render(){
return(
<div className="wrap">
<h1 onClick="iBeClicked">{this.props.data !== null ? this.props.data: 'Nothing' }</h1>
</div>
);
}
}
You use this.method.bind(this) in order to bind Component's this to React callback's execution inside render.

Transferring State Between Components - React

If I have a state in the App class, and I want to transfer those values into SecondApp, how do you go about that? I've tried using props but when I console log it, I get undefined.
Excuse the nooby question, I'm fairly new and trying to get my hands dirty, haha.
class App extends Component {
constructor(props) {
super(props)
this.state = {
todo: ['hello', 'hey']
}
}
}
class SecondApp extends Component {
render() {
return (
<p>?</p>
)
}
}
If you are passing the props correctly, they shouldn't turn up undefined. Props would be the correct way to go about this though!
class App extends Component {
constructor(props) {
super(props)
this.state = {
todo: ['hello', 'hey']
}
}
render() {
return <SecondApp testProp={this.state.todo}/>;
}
}
class SecondApp extends Component {
render() {
return <div>this is the prop: {this.props.testProp}</div>;
}
}
If you pass it through like that, you'll see the prop show up as "hellohey", check out the JSFiddle. Next off you'll likely want to render these items in a list, and will need to handle that accordingly. This article will point you in the right direction!
First you need to call SecondApp in App and then pass props.
class SecondApp extends React.Component {
render() {
return ( <
p > {this.props.todo} < /p>
)
}
}
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
todo: ['hello', 'hey']
}
}
render() {
return ( <
SecondApp todo = {
this.state.todo
} />
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
<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="app"></div>
If you mean to pass data from one app to another (that means, you render an app on an id and another app on another id) you can use events.
Whenever the state of the first app updates, you can dispatch an event and put an event listener on the other app, that updates it's state.
This is a common way to share data between independent modules/apps.
You can read more about this when you google "observer subscriber pattern".
Otherwise, if you mean to pass data to a child component, you really should read the react documentation.

Add methods to Higher Order Components in React

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>
)
}
}

Categories