How to access state of another component - javascript

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

Related

ReactJS: setState from outside [duplicate]

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

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

Multiple components within a file

Says I have component A
like
export default class ComponentA extends components {
render(){
return() //use componentB here?
}
}
class ComponentB extends components {
}
how can I create another component and use it within ComponentA?
How can I create another component and use it within ComponentA?
There are two possible ways of doing that:
1- Define the component in the same file, exporting of that component will be not required because you will use that component in the same file.
2- Define the component in another file then export that component. Importing of component will be required in this case.
We can create as many components as we want in the same file, and we can use those components in the same way as we use HTML tags div, span, p etc.
Example:
Using ComponentB inside another component ComponentA:
export default class ComponentA extends components {
render(){
return(
<div>
{/*other code*/}
<ComponentB /> // notice here, rendering ComponentB
</div>
)
}
}
Define ComponentB in same file like this:
class ComponentB extends components {
}
Define ComponentB like this in another file:
export default class ComponentB extends components {
}
Just use it, like any other component:
export default class ComponentA extends components {
render() {
return <ComponentB />; // Use ComponentB here
}
}
class ComponentB extends components {
render() {
return <div>I'm B</div>;
}
}
Example:
/*export default*/ class ComponentA /*extends components*/ extends React.Component {
render() {
return <ComponentB />; // Use ComponentB here
}
}
class ComponentB /*extends components*/ extends React.Component {
render() {
return <div>I'm B</div>;
}
}
ReactDOM.render(
<ComponentA />,
document.getElementById("react")
);
<div id="react"></div>
<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>
Yes, you are in the right track.
export default class ComponentA extends React.Component {
render(){
return(<ComponentB />);
}
}
class ComponentB extends React.Component {
render() {
return (<h1>Hello world! This is Component B</h1>)
}
}
or better yet, use stateless components like so: (if it's a really dumb component)
const ComponentB = () => (<h1>Hello world! This is Component B</h1>);

How to make/access state using props in react?

I made an app with multiple components and want their state to be accessed using parent/main app, I'm not sure how to get it. what i'm trying to do is when i change state in main "App" the component state should change. One of the component is 'checkbox' and now i want to access its state using parent app, I made multiple attempts but not getting it done. my code goes like this..
This is Main 'App' code:
import React, { Component } from 'react';
import Checkbox from './checkbox';
import Radio from './Radio';
import ToggleSwitch from './ToggleSwitch';
import PrimaryButton from './PrimaryButton';
class App extends Component {
onClick(isClicked){
isChecked:true
};
render() {
return (
<div id="form">
<Checkbox
onClick={this.onClick}
/>
<RadioButton
onClick={this.onClick}
/>
</div>
);
}
}
export default App;
The component i want to access goes like this:
import React, { Component } from 'react';
class Checkbox extends Component {
constructor(props){
super(props);
this.state={
isChecked:true
};
};
onCheck(){
this.setState({
isChecked: !this.state.isChecked
});
this.props.isClicked()
};
render() {
return (
<div>
<div
className={this.state.isChecked ? 'checked': 'unchecked'}
onClick={this.onCheck.bind(this)}
>
</div>
</div>
);
}
}
export default Checkbox;
You forgot to bind the onClick event in the app component, try this it will work :
class App extends Component {
onClick(isClicked){
console.log('isClicked', isClicked);
};
render() {
return (
<div id="form">
<Checkbox onClick={this.onClick.bind(this)}/>
</div>
);
}
}
If you already have onClick handler for the Checkbox I don't see why you couldn't just move the state up to the App component and just pass down a callback from there to the Checkbox that will update the parent state. That seems like a more React way to do it, to me.
class App extends Component {
constructor(props){
super(props);
this.state={
isChecked:true
}
}
onClick = (isClicked) => {
this.setState({isChecked: !this.state.isChecked})
}
render() {
return (
<div id="form">
<Checkbox
onClick={this.onClick}
ischecked={this.state.isChecked}
/>
</div>
);
}
}
Component
class Checkbox extends Component {
onCheck(){
this.props.onClick()
}
render() {
return (
<div>
<div
className={this.props.isChecked ? 'checked': 'unchecked'}
onClick={this.onCheck.bind(this)}
>
</div>
</div>
)
}
}

Categories

Resources