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>
)
}
}
Related
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'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 :)
I have below codes
chat.js
import React from 'react';
import '../styles/Chat.css';
import Web from '../services/Web';
class Chat extends React.Component {
constructor(props) {
super(props);
this.state = {
msg:''
};
this.sendMessage = this.sendMessage.bind(this);
}
sendMessage () {
this.props.updatecommentText(this.refs.newText.value, this.props.index);
this.setState({ msg: '' });
}
render() {
return (
<div className="Chat-container">
<div className="Chat-row">
<div className="Chat-column">
<div className="Chat-card">
<div className="Chat-body">
<div className="Chat-title">React Based Chatbot</div>
<div className="Chat-messages">
{ this.props.children }
</div>
</div>
<div className="Chat-footer">
<textarea className="Chat-input" ref="newText"></textarea>
<button className="Chat-submit" onClick={this.sendMessage} defaultValue={ this.props.children }>Send</button>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Chat;
Web.js
import React, { Component } from 'react';
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import Chat from '../components/Chat';
class Web extends React.Component {
constructor(props){
super(props);
this.state = {
messages:["Hi, How can I help you ?"
]
};
this.sendtobot = this.sendtobot.bind(this);
}
sendtobot(newText, i){
var arr = this.state.messages
arr.push(newText)
this.setState({messages: arr})
}
eachMessage(message, i){
return (<Chat key={i} index={i} updatecommentText={ this.sendtobot.bind(this) }>{ message }</Chat>);
}
render(){
return(
<div>
{this.state.messages.map(this.eachMessage.bind(this))}
</div>
)
}
}
export default Web;
I wanted to take the input from the Chat.js and send it to Web.js and push that value to array messages and then again render that array in the this.props.children in Chat.js
But, while running the code, I am getting an error this.props.updatecommentText is not a function.
Can someone please help me with this.
You have bind this.sendtobot twice. It should be only in the constructor.
like this
eachMessage(message, i){
return (
<Chat key={i} index={i} updatecommentText={this.sendtobot}>
{ message }
</Chat>
);
}
Your code seems to work.
Here is a sandbox with your code.
I'm not sure it works as you would expect, but it works without errors.
By changing this 3 functions in Web component, it starting to look like a chat with only one textarea
sendtobot(newText, i) {
this.setState({ messages: [...this.state.messages, newText] })
}
eachMessage(message, i) {
return (<p>{message}</p>);
}
render() {
return (
<div>
{this.state.messages.map(this.eachMessage.bind(this))}
<Chat updatecommentText={this.sendtobot}/>
</div>
)
}
You can pass child's component state to parent component using redux also as global state.
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} />
}
}
I wants to create a class which while load a react.js file into a div specified using the react i had not found any thing related to that on net.
Check this example:
Lets say you have 2 component App and Child, and wants to render child component on checking the checkbox, this is called conditional rendering.
app.js file, import file child.js in App component:
import Child from './child';
class App extends React.Component {
constructor() {
super();
this.showComments = this.showComments.bind(this);
this.state = {
showComponent: false,
};
}
showComments(e) {
this.setState({
showComponent: e.target.checked,
});
}
render() {
return (
<div className="add_checkbox">
<span>Enable Comments</span>
<input className="checkbox" type="checkbox" name="enable_comment" onClick={this.showComments} value="enable_comment"/>
{this.state.showComponent ? <Child/> : null}
</div>
)
}
}
child.js file:
export default class Child extends React.Component{
render(){
return(
<div>Hello</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('container'));
Check fiddle for working example: https://jsfiddle.net/ztx9kd1w/
Let me know if you need any help.