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} />
}
}
Related
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>
)
}
}
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.
I have an App component and a function 'modalToggled' inside its.
I want to pass the function to multiple child components until I get to the last one, the 'interiores' component.
Like this:
<App> -> <Coluna1> -> <MenuPrincipal> -> <Portfolio> -> <PortfolioMenu> -> <interiores>
App Component, the parent of all components:
import React, { Component } from 'react';
import Coluna1 from './Coluna1'
class App extends Component {
constructor(props) {
super(props)
this.state = {
modalOn: false
}
this.modalToggled = this.modalToggled.bind(this)
}
modalToggled = (on) => {
this.setState({modalOn: on});
}
render() {
return (
<div>
<Coluna1 onModalToggle={this.modalToggled}/>
</div>
)
}
}
export default App;
This is the 'Coluna1' the first child component. I did the same thing in the another ones: 'MenuPrincipal', 'Portfolio', 'PortfolioMenu'
class Coluna1 extends Component {
constructor(props){
super(props)
}
render() {
return (
<div>
<Header />
<MenuPrincipal onModalToggle={this.props.modalToggled} />
</div>
)
}
}
export default Coluna1
Therefore here is the last component interiores, when I click on the button there appears an error message:
TypeError: _this.props.onModalToggle is not a function
import React, { Component } from 'react'
import Modal from 'react-responsive-modal';
class Interiores extends Component {
constructor(props) {
super(props)
this.state = {
open: false
}
}
onOpenModal = () => {
this.setState({ open: true });
this.props.onModalToggle(true);
};
onCloseModal = () => {
this.setState({ open: false });
this.props.onModalToggle(false);
};
render() {
const { open } = this.state;
return (
<div>
<button onClick={this.onOpenModal}>Open modal</button>
<Modal open={open} onClose={this.onCloseModal} center></Modal>
</div>
)
}
}
export default Interiores;
Does anybody know how to solve it? Thank you
It happens, because in App class you pass prop with name onModalToggle:
<Coluna1 onModalToggle={this.modalToggled}/>
But in Coluna1 you receive this props with wrong name, modalToggled:
<MenuPrincipal onModalToggle={this.props.modalToggled} />
Just make the names of props equal. In Coluna1 and other intermediate components pass and receive this props as onModalToggle:
<MenuPrincipal onModalToggle={this.props.onModalToggle} />
This is the problem
modalToggled = (on) => {
this.setState({modalOn: on});
}
Since this is a class function it needs to be defined like
modalToggled(on) {
this.setState({modalOn: on});
}
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>
)
}
}
I am currently having a problem rendering a React wrapper component in another component. Basically, I export default the wrapper component (CreatePage), and then try to import it into another component (EditPage), but am getting the error "Cannot read property pageType of undefined." pageType is a prop for CreatePage that I define, but the weird thing is I have debuggers in the render functions of both Components and neither is being hit, so I think there's an issue with the component itself for some reason but I'm not sure quite what. Here is the code from the EditPage for some context:
import React, { Component, PropTypes } from 'react';
import CreatePage from './CreatePage';
import withResource from '../../../../lib/withResource';
export class EditPage extends Component {
constructor(props){
super(props);
}
render() {
debugger;
return (
<div>
<CreatePage pageType={'edit'}/>
</div>
);
}
}
export default withResource(
{
name: 'EditResource',
key: 'hello',
},
EditPage);
Code for CreatePage:
export default class CreatePage extends Component {
constructor(props) {
super(props);
}
headerTitles = {
'create': i18n._('Create', '[m10n]'),
'edit': i18n._('Edit', '[m10n]'),
}
renderHeader(pageType) {
return (
<div className={cx('headerWrapper')}>
<div className={cx('header')}>
<div className={cx('title')}>
{this.headerTitles[pageType]}
</div>
</div>
</div>
);
}
renderCreateEditPage(pageType) {
return (
<div>
{this.renderHeader(pageType)}
<div className={cx('contentWrapper')}>
<div>
<NameTag type={'pageType'}/>
</div>
</div>
</div>
);
}
render() {
return (
<div className={cx('pageWrapper')}>
{this.renderCreateEditPage(this.props.options.pageType)}
</div>
);
}
}
CreatePage is looking in this.props.options.pageType but you just passed in pageType directly.. no mention of an options prop