ReactJS: setState from outside [duplicate] - javascript

This question already has answers here:
How to update the state of a sibling component from another sibling or imported component in REACT
(3 answers)
Closed 1 year ago.
This is my App.js
import React from 'react';
import './App.css'
import Tools from './components/class/Tools'
import Loading from './components/inc/Loading'
export default class App extends React.Component {
componentDidMount() {
Tools.showLoading();
}
render() {
return (
<div className="App">
<Loading />
</div>
)
}
}
Loading.js:
import React from 'react'
export default class Loading extends React.Component {
constructor(props) {
super(props)
this.state = {
display: 'none'
}
}
render() {
return (
<div className="loading" style={{display: this.state.display}}>
<span></span>
</div>
)
}
}
I want change display of Loading from Tools.js:
export default class Tools extends React.Component {
static showLoading(){ // or non-static
Loading.setState ...
}
}
How I can access and setState variable from another class or function or outside?

Your Loading and Tools components are siblings, so it is harder to pass data between them.
You should pull the state out to the parent App component, then you can pass in the setState callback method and the state.loading variable into the Tool and Loading components as a prop.
Or you can re-use your Loading component within all the other components, like so:
export default class Tool extends React.Component {
constructor(props) {
super(props)
this.state = {
loading: true
}
}
render() {
return (
<Loading isloading={loading}>
<div>
// content here
</div>
)
}
}

Related

How to pass component to onClick in react

import React from 'react'
export default () => {
function clickHandler() {
console.log('Button clicked')
}
return (
<div>
<button onClick={clickHandler}>Click</button>
</div>
)
}
In the above code we see that a function has been passed to the onClick.In the same way to the onClick I need to pass a diffrent component which is present in the same src. This component consists of a .js and a .css file.Could you please help me out with it. Thanks in advance
If you don't mind using classes instead of functions, your other component should look like this:
import React from 'react'
class ShowThisAfterClick extends React.Component {
return (
<div>
<p>This is what you want to show</p>
</div>
)
}
export default ShowThisAfterClick
And now you should update the component you've shown:
import React from 'react'
import ShowThisAfterClick from './where/you/put/the/ShowThisAfterClick.js'
class Main extends React.Component {
constructor(props){
super(props)
this.state = { isButtonClicked: false }
this.clickHandler = this.clickhandler.bind(this)
}
clickHandler() {
this.setState({ isButtonClicked: true })
}
render() {
const { isButtonClicked } = this.state
return (
<div>
<button onClick={ this.clickHandler }>Click</button>
{ isButtonClicked ? <ShowThisAfterClick /> : ''}
</div>
)
}
}
export default Main
If you want to keep using functions, then I would kindly suggest to read the manual, it is more than well written.

react child state doesn't update with props from father (and deeper in the branch)

The problem is following:
I have components: Grandfather, father and child (literally :D).
Grandfather passes his state through props to father (and father sets his state with it).
Then father passes props to child and child also sets state with it.
When i display this.props everything is fine, but when i display
state then i see that nothing has changed in father and child.
I heard there is something like componentWillReceiveProps() but it is already deprecated.
Working example: https://codesandbox.io/s/doesitworkornot-rrcgt?fontsize=14&hidenavigation=1&theme=dark
And codes:
Grandfather.js
import React from "react";
import Father from "./Father";
class GrandFather extends React.Component {
constructor(props) {
super(props);
this.state = {
clickedCounter: 1
};
}
onClick = e => {
this.setState(prevState => ({
clickedCounter: prevState.clickedCounter + 1
}));
};
render() {
return (
<div>
<button onClick={this.onClick}>Press me</button> <br />
Here is Grandfather -> state value={this.state.clickedCounter}
<Father clickedCounter={this.state.clickedCounter} />
</div>
);
}
}
export default GrandFather;
Father.js
import React from "react";
import Child from "./Child";
class Father extends React.Component {
constructor(props) {
super(props);
this.state = {
clickedCounter: this.props.clickedCounter
};
}
render() {
return (
<div>
Here is Father -> props value={this.props.clickedCounter} <br />
Here is Father -> state value={this.state.clickedCounter}
<Child clickedCounter={this.props.clickedCounter} />
</div>
);
}
}
export default Father;
Child.js
import React from "react";
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
clickedCounter: this.props.clickedCounter
};
}
render() {
return (
<div>
Here is Child -> props value={this.props.clickedCounter} <br />
Here is Child -> state value={this.state.clickedCounter}
</div>
);
}
}
export default Child;
I also heard there is something like cloning children... I'd like to avoid it if possible.
When you initialise state from props, react will not refresh state but it do refresh props. You can use below code to make it work instead of componentWillReceiveProps.
static getDerivedStateFromProps(nextProps) {
return {
clickedCounter: nextProps.clickedCounter,
}
}

How to pass a click handler to a child component

I'm trying to pass a click handler function to a child component but I cant figure out why its not working.
I tried making my click handler into a lambda function, binding it to the parent component, and making my onClick in the child component a lambda function but nothing seems to work.
Parent Component
import React from 'react';
import NavMenuButton from './navMenuButton.js';
export default class NavBar extends React.Component {
constructor(props) {
super(props);
this.state = {
navBarOpen: true
};
this.toggleNavbar = this.toggleNavbar.bind(this);
}
toggleNavbar() {
console.log('Toggled!');
this.setState({
navBarOpen: this.state.navBarOpen ? false : true
});
}
render() {
return (
<NavMenuButton
handleClick={this.toggleNavBar}
navBarOpen={this.state.navBarOpen}
/>
);
}
}
Child Component
import React from 'react';
export default class NavMenuButton extends React.Component{
constructor(props){
super(props)
}
render(){
const styles = {
navButton: this.props.navBarOpen
? {fontSize:26, cursor:'pointer', userSelect:'none'}
: {fontSize:26, cursor:'pointer', userSelect:'none'}
}
return(
<div>
<span
style={styles.navButton}
onClick={this.props.handleClick}
>
{'\u2630'}
</span>
{this.props.navBarOpen
? <p>its open</p>
: <p>its closed</p>}
</div>
);
}
}
This configuration is what I thought should work, but if I log the props in navMenuButton to the console, handleClick is undefined which really confuses me
toggleNavBar !== toggleNavbar - case sensitivity is very important :)

How to access state of another component

I have home component with header component how may I access the header states in home component here is the example
Header.JS
class Header extends React.Component {
constructor(props){
super(props);
this.state = {
pageNumber: 1
}
}
render() {
return (
<div className="shopping-list">
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
Home.js
import React, {Component} from 'react';
import Header from './header';
class App extends Component {
render() {
return (
<div>
<Header /> // I need to use the states of Header in this component
</div>
)
}
}
export default App;
I need to use the states of Header in Home component, is that possible?
Does this way is good for performance?
Thank you
You need to use state lifting.
Define a method e.g. liftTheState in Header component which will lift the state of Header component by calling Home component method with required data.
class Header extends React.Component {
constructor(props){
super(props);
this.state = {
pageNumber: 1
}
}
liftTheState=()=>{
this.props.callHomeMethod(this.state.pageNumber);
}
render() {
//...
}
}
In Home :
Define a method e.g. callHomeMethod in Home component which will hold the Header component data and passed the method as a prop to Header component
class App extends Component {
callHomeMethod = (someDataFromHeader)=>{
}
render() {
return (
<div>
<Header callHomeMethod = {this.callHomeMethod}/> // pass Home method here used for state lifting.
</div>
)
}
}

How can I update the Youtube video using my search function?

I am trying to pass a search query from an input in searchBar.js to app.js and then back into its child Video in order to search for a video and play it.
I am not sure what I'm doing wrong, as the video is not updating.
Do I need to rerender the video component or something like that?
I am using the react-youtube module for react integration with the YoutubeAPI.
https://github.com/kdelalic/Shuffle
app.js (parent) class:
import React, { Component } from 'react';
import "../css/app.css";
import Video from "./video";
import TopBar from "./topBar";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
searchQuery: null
};
}
myCallback(dataFromChild) {
this.setState({ searchQuery: dataFromChild });
}
render() {
return (
<div>
<TopBar parentCallBack={this.myCallback}/>
<Video query={this.state.searchQuery} />
</div>
);
}
}
topBar.js class:
import React, { Component } from 'react';
import {Navbar} from 'react-materialize';
import '../css/topBar.css';
import SearchBar from './searchBar'
export default class TopBar extends Component {
myCallback(dataFromChild) {
this.props.parentCallBack(dataFromChild);
}
render() {
return (
<div className="wrapper">
<Navbar className="logo" brand='Shuffle+' right>
<SearchBar callBack={this.myCallback}/>
</Navbar>
</div>
);
}
}
searchBar.js class:
import React, { Component } from 'react';
import {NavItem, Icon} from 'react-materialize';
import '../css/searchBar.css';
export default class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
this.props.callBack(this.state.value);
event.preventDefault();
}
render() {
return (
<div className="wrapper">
<form className="form" onSubmit={this.handleSubmit}>
<label>
<input className="input" type="text" value={this.state.value} onChange={this.handleChange} />
</label>
</form>
<NavItem className="searchButton">
<Icon>search</Icon>
</NavItem>
</div>
);
}
}
This looks relatively ok with one exception.
myCallback(dataFromChild) {
this.props.parentCallBack(dataFromChild);
}
// ...when being used
<SearchBar callBack={this.myCallback}/>
The problem is, when the callBack function is called from the Child, the this of the function is set to the child component.
You have a couple options here when passing a function into a child as a callback.
Bind in property
<SearchBar callBack={this.myCallback.bind(this)}/>
The downside is that the function is copied every time the render function is called.
Bind in constructor
As you've already done, you can bind the this context of the function to the parent in the constructor.
class TopBar extends Component {
constructor() {
// ...
this.myCallback = this.myCallback.bind(this);
}
}
Downside is that it's terse and you have to write this for every function you need to bind to the component.
ES Class Property Arrow Functions
This is my personal favorite. The downside is that you need babel and the stage 2 proposal to transpile your code.
class TopBar extends Component {
myCallback = () => {
// ...
}
render() {
<SearchBar callback={this.myCallback} />
}
}

Categories

Resources