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
Related
I'm new to React and I have the following react components that I'm using in a Blazor WASM App.
// Parent
export class Parent extends React.Component{
constructor(props){
super(props);
this.childRef = React.createRef();
// saving reference to component to access it using Blazor JS Interop
window.canvasComponentRef = this
}
render(){
return <Child ref={this.childRef} />
}
parentFoo = () => {
this.childRef.current.foo();
}
}
// Child
export class Child extends React.Component{
constructor(props){
super(props);
}
render(){
return <div> Content </div>
}
foo(){
// some actions in child
}
}
I render the component using...
ReactDOM.render(Parent, document.getElementById('root'));
Result: childRef.current work
When the user navigates away from the Parent component page, I unmount it manually using...
ReactDOM.unmountComponentAtNode(document.getElementById('root'));
When the user comes back to the Parent component page, I render it again using...
ReactDOM.render(Parent, document.getElementById('root'));
Now, when I call window.canvasComponentRef.parentFoo(), childRef.current is null.
Can anyone explain why?
Thank you!
My issue was actually the global variable at
// saving reference to component to access it using Blazor JS Interop
window.canvasComponentRef = this
After refactoring it to get a ref to the Parent component using callback refs as below, the issue got resolved.
let parentRef = null;
function handleRef(element){
parentRef = element;
}
function renderParent(){
const parent = <Parent ref={this.handleRef}/>
ReactDOM.render(parent, document.getElementById('root'));
}
// Now call parent method like below:
function callParentFoo(){
parentRef.parentFoo();
}
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...
}
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'))
I'm working on a react based app and I am checking user's permission before rendering some piece of jsx using a HasRole component. Everything works fine except if I have a function as a child of the HasRole component, the function is getting called every time the parent component renders, if the user doesn't have permission also. How do I prevent this from happening.
HasRole.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
class HasRole extends Component {
render() {
const { children, role, requiredRole } = this.props;
if(!requiredRole.includes(role)) return null;
return children;
}
}
const getMapStateToProps = (extendWith = {}) => state => {
return {
role: state.auth.userType,
...extendWith
}
}
export default connect(getMapStateToProps)(HasRole);
And when I use the HasRole component to check permission, {this.renderUsers} is executed if user don't have permission also.
MovieShow.js
import React, { Component } from 'react';
import HasRole from '../has-role';
class MovieShow extends Component{
constructor(props){
super(props);
}
renderUsers(){
...
}
render(){
return(
...
<HasRole requireRole={["admin"]}>
{this.renderUsers} // this will run if user is not admin also but the component wont be shown
</HasRole>
}
}
Thanks in advance!
Make the rendersUsers a stateless functional component by dragging it out of the class instead.
https://reactjs.org/docs/components-and-props.html
By doing this it should enable you to pass the requireRole param to it, and lock it behind permissions aswell.
The reason that renderUsers is executed is because it is evaluated in Parent although rendered as children in HasRole. You could write your HasRole component to use used with renderProps like
class HasRole extends Component {
render() {
const { children, role, requiredRole } = this.props;
if(!requiredRole.includes(role)) return null;
return children();
}
}
and then you would use it like
class MovieShow extends Component{
constructor(props){
super(props);
}
renderUsers(){
...
}
render(){
return(
...
<HasRole requireRole={["admin"]}>
{() => {return this.renderUsers()}}
</HasRole>
}
}
I am a beginner in react js, before react I was working with angular2 and backbone,and now my problem is I want to create a class such that all of my requests send from this class,like this:
class Ext {
get(url){
$.ajax({
url : url,
success : function(res){},
and ......
});
}
}
in my another component that use from my Ext function :
export default Ext;
import React from 'react';
import {render} from 'react-dom';
import {Ext} from "./module/Ext"
class App extends React.Component {
constructor(props) {
super(props);
/// Ext.get();
}
render () {
return(
<p> Hello React!</p>
);
}
}
render(<App/>, document.getElementById('app'));
how to extends from Ext ??? what is the best way ?
If your get(url) method is something general, it would be wise to have it as part of a separate module, then import and use it in any component you would like.
If, on the other hand, you want to implement a functionality right into a react component, the new ES2015 way of doing it would be by using Composition.
You first create what's called a HOC (Higher order component), which basically is just a function that takes an existing component and returns another component that wraps it. It encapsulates your component and gives it functionality you want, like with mixins but by using composition instead.
So your example would look like something like this:
import React from 'react';
export default const Ext = (Component) => class extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
let result = this.get('some_url').bind(this)
this.setState({ result })
}
get(url) {
$.ajax({
url : url,
success : function(res){
return res;
}
});
}
render() {
// pass new properties to wrapped component
return <Component {...this.props} {...this.state} />
}
};
Then you can just create a stateless functional component and wrap it with the HOC:
import React from 'react';
import Ext from './module/Ext';
class App {
render () {
return <p>{this.result}</p>;
}
}
export default Ext(App); // Enhanced Component
Or using ES7 decorator syntax:
import { Component } from 'react';
import Ext from './module/Ext';
#Ext
export default class App extends Component {
render () {
return <p>{this.result}</p>;
}
}
You can read this post for more details: http://egorsmirnov.me/2015/09/30/react-and-es6-part4.html