React.js passing data from class component to another in ReactDOM.render - javascript

I have this problem where I want to update my component FooBar if Foo's state changes. How can I do it? This doesn't work.
import React from "react"
import ReactDOM from "react-dom"
import FooBar from "./FooBar"
class Foo extends React.Component {
constructor() {
super()
this.state = { data: [] }
}
changeData() {
someCode
}
render() {
return (
some html
)
}
}
ReactDom.render(<Foo />, document.getElementById('Something'))
ReactDom.render(<FooBar data={this.state.data}/>, document.getElementById('SomethingElse'))

Question is a bit confusing, You can try this if it works
changeData = () =>
this.setState({data:'your changes'})
}
the above code will update the state, thus rest of component connected with class will render automatic.

Create a parent component, render both foo and foobar inside. now you can use state normally for communication between them and only have to use one ReactDom.Render
class Parent extends React.Component{
render(){
return(
<div>
<Foo/>
<Foobar/>
</div>
);
}
}
ReactDom.render(<Parent />, document.getElementById('Something'))

Related

How to properly render Component after this.setState in React

I have this React component
import React, { Component } from "react";
export default class ResourceForField extends Component {
constructor() {
super();
this.state = {
resources: [],
};
}
componentDidMount() {
// get the resources from the Link props and save it into the state
this.setState({
resources: this.props.location.resources,
});
}
// This component gets the id of current learningField from the url
// and the rest(like the resources) from the Link component
render() {
return (
<div>
{this.state.resources.map(res => (
<div>test</div>
))}
</div>
);
}
}
It gets the resources from the Link component, and that works fine. If I check out the state of the Component from the dev tools, the state looks right. And I thought with my logic this should work. So firstly, the state is empty, the component gets rendered, since the state is empty it doesn't render any components. Then, setState gets called, it gets all the resources and saves them into the state, and then the component would re-render, and it should work, but it doesn't. I'm getting a TypeError: Cannot read property 'map' of undefined error. What is the correct way to do this and how do I fix this?
Try this code:
import React, { Component } from "react";
export default class ResourceForField extends Component {
constructor() {
super();
this.state = {
resources: this.props && this.props.location && this.props.location.resources?this.props.location.resources:[],
};
}
componentDidMount() {
}
// This component gets the id of current learningField from the url
// and the rest(like the resources) from the Link component
render() {
return (
<div>
{this.state.resources.map(res => (
<div>test</div>
))}
</div>
);
}
}
Or use directly props
import React, { Component } from "react";
export default class ResourceForField extends Component {
constructor() {
super();
}
// This component gets the id of current learningField from the url
// and the rest(like the resources) from the Link component
render() {
return (
<div>
{
this.props && this.props.location &&
this.props.location.resources
?this.props.location.resources.map(res => (
<div>test</div>
))
:null
}
</div>
);
}
}
Or use componentWillReceiveProps or getDerivedStateFromProps life cycle methods.
Check this.props.location.resources is array.
See more: https://hackernoon.com/replacing-componentwillreceiveprops-with-getderivedstatefromprops-c3956f7ce607
For first check is this.props.location.resources array, or if data type changes you can add checking, you can use lodash isArray or with js like this:
import React, { Component } from "react";
export default class ResourceForField extends Component {
constructor() {
super();
this.state = {
resources: [],
};
}
componentDidMount() {
// get the resources from the Link props and save it into the state
Array.isArray(this.props.location.resources) {
this.setState({
resources: this.props.location.resources,
});
}
}
// This component gets the id of current learningField from the url
// and the rest(like the resources) from the Link component
render() {
return (
<div>
{this.state.resources.map(res => (
<div>test</div>
))}
</div>
);
}
}
Or you can just use hooks like this:
import React, { useState, useEffect } from "react";
export default function ResourceForField({location}) {
const [ resources, setResources ] = useState([]);
useEffect(() => {
if (location && Array.isArray(location.resources)) {
setResources(location.resources)
}
}, [location]);
return (
<div>
{resources.map(res => (
<div>test</div>
))}
</div>
);
}
If the internal state of ResourceForField doesn't change and always equals to its prop, you shouldn't save the prop in the state. You can instead create a pure functional component.
Also note that there's nothing preventing you from initializing the state from the props in constructor method. i.e. you're not required to wait for the component to mount in order to access the props.
So, I'd write the following component for ResourceForField:
function ResourceForField({resources = []}) {
return (
<div>
{
resources.map(res => (<div>test</div>))
}
</div>
);
}

Access to variables between components

I have two components App and SomeComponent.
I want to get access variable in App from SomeComponent.
App:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
var places = [];
class App extends Component {
state = {isLoading:true}
render(){
bla-bla...}
}
export default App;
SomeComponent:
import React from 'react'
import App from '../App'
class SomeComponent extends React.Component {
componentDidMoint(){
console.log('Check access places array',App.places)
}
render(){
bla-bla...
}
}
export { SomeComponent }
But its coughed out places is Undefined, instead of show empty array. Whats wrong here ?
Yes, I've tried different variants... but no success.
Thanks!
The way to pass data from a parent component to a child component in React is through props. You can e.g. pass the array as the places prop to your Child component and access it from this.props.
Example
class App extends React.Component {
state = { isLoading: true, places: ['foo', 'bar'] }
render() {
return <Child places={this.state.places} />
}
}
class Child extends React.Component {
componentDidMount() {
console.log('Check access places array', this.props.places)
}
render() {
return <div>Child</div>
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Don't import App into Child. In App, use React's render method with JSX to declare an instance of child. In App's Child JSX, the attributes will become available as "props" within Child. See https://reactjs.org/docs/components-and-props.html React expects a programmatic structure that's not as "free" as straight JS, but React then provides a concise, integrated way to make widgets and SPAs.
you need to export place from App
export const places = [];
And also in child.app
import React from 'react'
import { places } from '../App'
class Child extends React.Component {
componentDidMoint(){
console.log('Check access places array',places)
}
render(){
bla-bla...
}

Variable not defined (TypeError: Cannot read property 'todos' of null) ReactJS

This is all my code below .
When I run it I receive this error (TypeError: Cannot read property 'todos' of null )todos not found at this line var todos=this.state.todos;
My App.js file
import React, { Component } from 'react';
class App extends Component {
getInitialState (){
return{
todos:['washup',"hi","hello","up"]
}
}
render() {
var todos=this.state.todos;
Added Code here
todos=todos.map(function(item,index){
return(
<li>item</li>
);
}
);
Till here
return (
<div id="App">
<ul>{todos}</ul>
)
} )
</div>
);
}
}
export default App;
This is my index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from `'./registerServiceWorker';`
ReactDOM.render(<div>
<App>Here is my Buttonas</App>
</div>, document.getElementById('root'));
registerServiceWorker();
EDIT
New Error
TypeError: Cannot read property 'map' of undefined
At this line todos=todos.map(function(item,index){
What is the error now?
getInitialState() is only used with createReactClass(). When using ES6 classes you just set state as a property:
See Setting the Initial State in the react docs:
In ES6 classes, you can define the initial state by assigning
this.state in the constructor:
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: ['washup',"hi","hello","up"],
}
}
// ...
}
or just
class App extends Component {
state = {
todos: ['washup',"hi","hello","up"],
}
// ...
}
With createReactClass(), you have to provide a separate
getInitialState method that returns the initial state:
var App = createReactClass({
getInitialState: function() {
return {
todos: ['washup',"hi","hello","up"],
};
},
// ...
});
You're initializing the state older way in a newer version of reactjs. I already appreciate the answer of trixn. But here's also a solution without removing your current code:
class App extends Component {
state = getInitialState (){
return{
todos:['washup',"hi","hello","up"]
}
}
Notice that I have assigned state to the getInitialState and will work fine because this returns the object {todos:['washup',"hi","hello","up"]} which is similar to this:
state = {todos:['washup',"hi","hello","up"]}
Next, when your component is being rendered first time your todos might get undefined as you stated. To resolve this issue you may add a condition:
todos && todos.length && todos.map(...)
Now, the map function will only run if the todos is not undefined and it has length ie. it has at least one value.
It caused because you didn't define todos in your state, to achieve the soloution, make a constructor in your class and set a todos variable in your state, you can set in empty or null in the constructor and fill it later, then you can use it in your render section, comment if you need further information and also read react life cycle in the official website
With createClass you can use getInitialState:
const App = React.createClass({
getInitialState() {
return { /* initial state */ };
},
});
but with ES6 classes you do like this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {todos:['washup',"hi","hello","up"]};
}
}
EDITED: get items through map:
class App extends Component {
state={
todos: ['washup', "hi", "hello", "up"]
}
render() {
var todos= this.state.todos.map((item)=>{
return <li>{item}</li>
})
return (
<div id="App">
<ul>{todos}</ul>
</div>
)
}
}
Try this. You should define you todos in the state
App.Js
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
class App extends Component {
constructor(props) {
super(props);
this.state ={
todos:['washup',"hi","hello","up"]
}
}
render() {
return (
<div id="App">
<ul>{this.state.todos}</ul>
</div>
);
}
}
export default App;

Call component function from a JS File

I want to know If I can do this in react, I want to call a function or method of a react component from a JS file, so I could change the state of that component.
I have these three files for example
First App.js
import React,{Component} from 'react';
import Login from './Login';
class App extends Component{
constructor(){
super();
this.state = {session:false}
}
changeStateSession(state_session){
this.setState({session:state_session});
}
render(){
return(
this.state.session
?<div>Content</div>
:<Login/>
);
}
}
Login.js
import React, {Component} from 'react';
import Auth from './Auth.js';
class Login extends Component{
constructor(){
super();
}
login(){
Auth.login();
}
render(){
return(
<button onClick={(e)=>login(e)}></button>
);
}
}
And Auth.js
import App from './../../App.js';
const Auth = {
login:App.changeStateSession(true)
};
export default Auth;
What I really want to know is if theres a way that I could call the App function (changeStateSession) from the Auth.js file, the Auth.js file is just an example of what I would like to achieve I know this file doesn't work, but I would like to know If there is a way to achieve something like this in react, hope you can help me , thanks.
The more common way of doing something like this would be to pass your changeSessionState function as a prop to the Login component.
App.js:
class App extends Component {
constructor(props) {
super(props);
this.state = { session: false }
this.changeStateSession = this.changeStateSession.bind(this);
}
changeStateSession(stateSession){
this.setState({ session: stateSession });
}
render(){
return (
this.state.session
? <div>Content</div>
: <Login onSuccess={() => this.changeStateSession(true)} />
);
}
}
Login.js:
class Login extends Component {
constructor(props) {
super(props);
}
login(){
// If your login process is asynchronous
// and returns a Promise, for example
Auth.login()
.then(this.props.onSuccess);
}
render() {
return (
<button onClick={(e)=> this.login(e)}></button>
);
}
}
Now, when this.props.onSuccess is called once your login succeeds, your App component's state will be updated since your changeStateSession method was passed as a prop to your Login component.
The big takeaway here is that if you want to update a parent's state from a child component, passing functions from your parent component to the child component is the way to typically handle it. No other way of updating parent state from a child is recommended.
Also, if there is an absolute necessity to call the changeStateSession function from your Auth.js file, then it's a very similar concept. Just pass the function through and call it there instead.
You should probably use props. Either calling passing the function to a child component or just passing the value to the App component as a prop and calling the function in the parent component

Reactjs:Is it possible to use Parent component property from another Parent's child component

I have a file named separatefile.jsx, in this file parent component name is Content and child component name is Child.
separatefile.jsx
import React from 'react';
import Parent from './learning.jsx';
class Content extends React.Component {
constructor() {
super();
this.state = {
finding : 'i am finding'
}
}
render() {
return (
<div>
<Child childprop={this.state.finding}/>
<Parent/>
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
<h2>{this.props.childprop}</h2>
<h1>child class property</h1>
</div>
);
}
}
export default Content;
This is another file named as learning.jsx , this file has Parent component named as Parent and Child component named as a Children.
My questions is that i need to access Parent component property(parent component for learning.jsx) from Child component(child component for separatefile.jsx file)...
learning.jsx
import React from 'react';
class Parent extends React.Component {
constructor() {
super();
this.state = {
searching : 'i will find the solution'
}
}
render() {
return (
<div>
<Children childrenprop={this.state.searching}/>
</div>
);
}
}
class Children extends React.Component {
render() {
return (
<div>
<h2>{this.props.childrenprop}</h2>
</div>
);
}
}
export default Parent;
If I understood you correctly, you want to use Parent's state in your Children component?
You can pass it down the component tree as props, e.g.:
class Content extends React.Component {
constructor() {
super();
this.state = {
finding : 'i am finding'
}
}
render() {
return (
<div>
<Child childprop={this.state.finding}/>
<Parent finding={this.state.finding} />
</div>
);
}
}
class Parent extends React.Component {
constructor() {
super();
this.state = {
searching : 'i will find the solution'
}
}
render() {
return (
<div>
<Children finding={this.props.finding} childrenprop={this.state.searching}/>
</div>
);
}
}
class Children extends React.Component {
render() {
return (
<div>
<h2>{this.props.childrenprop}</h2>
<div>{this.props.finding}</div>
</div>
);
}
}
It's probably not a direct answer but if you are starting a new app I would recommend you to use Redux with react-redux.
Redux is a predictable state container for JavaScript apps.
It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.
It's very small library so it's easy to understand how everything works. It might be a good solution to your problem.
Todo app example
You can also check out awesome egghead.io free tutorial - Getting Started with Redux
Here is the answer about the redux benefits by its author Dan Abramov
The React documentation provides an answer.
For communication between two components that don't have a
parent-child relationship, you can set up your own global event
system. Subscribe to events in componentDidMount(), unsubscribe in
componentWillUnmount(), and call setState() when you receive an event.
Flux pattern is one of the possible ways to arrange this.

Categories

Resources