I am new to React and I am finding it difficult to pass props from one component to another.
This is the first component
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
// show:true
};
}
counter = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div className="">
<div>{this.state.count}</div>
</div>
);
}
}
and this is the second
export default class Button extends React.Component {
render() {
return (
<div className="">
<App />
<button onClick={this.counter}>Click me</button>
</div>
);
}
}
How do I make the counter count by passing props in the apps component
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
// show:true
};
}
counter = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div className="">
<div>{this.state.count}</div>
<Button counter={this.counter} />
</div>
);
}
}
export default class Button extends React.Component {
render() {
return (
<div className="">
<button onClick={this.props.counter}>Click me</button>
</div>
);
}
}
Related
function Welcome(props) {
console.log("Welcome Back");
}
class App extends React.Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
<Welcome />
}
render(){
return (
<div>
<button onClick={this.handleClick}>CLICK HERE </button>
</div>
);
}
}
Why function handleClick can't call outer function Welcome? is there any solution to this?
To call that function, you should do as follows:
function welcome(props) {
console.log("Welcome Back");
}
class App extends React.Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
}
render(){
return (
<div>
<button onClick={this.handleClick}>CLICK HERE </button>
</div>
);
}
}
Notice that I've lowercased your Welcome function since Pacalcased function names should be reserved for React Components as a general naming convention.
If your intention is to have Welcome be a React component, then it should return some JSX and then you should render that out inside of the render function of your class component:
function Welcome(props) {
return (<div>Welcome Back!</div>
}
class App extends React.Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
welcome()
}
render(){
return (
<div>
<Welcome />
<button onClick={this.handleClick}>CLICK HERE </button>
</div>
);
}
}
If you'd like to hide your welcome message until you click the button, you can use state:
function Welcome(props) {
return (<div>Welcome Back!</div>
}
class App extends React.Component {
constructor(props){
super(props);
this.state = {
showWelcomeMessage: false
}
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
this.setState({showWelcomeMessage: true})
}
render(){
return (
<div>
{this.state.showWelcomeMessage ? <Welcome /> : null}
<button onClick={this.handleClick}>CLICK HERE </button>
</div>
);
}
}
In your example changing <Welcome /> to Welcome() is enough. But you should use camelCase to define functions. But here is the refactored version.
import React from "react";
const welcome = () => {
console.log("Welcome Back");
};
export default function App() {
const handleClick = () => {
welcome();
};
return (
<div>
<button onClick={handleClick}>CLICK HERE </button>
</div>
);
}
Just change the calling of the outer function "Welcome", because it is not a Component:
handleClick(){
Welcome()
}
UPDATE: My code checked out just fine. The issue was that a stopPropagation() was called in a separate Javascript library that prevented my onClicks from working.
--
I have a "MenuLink" react component in which I've added an onClick listener to an 'a' tag. The "MenuLink" component is imported from a "MenuItem" component which is imported from a "MainMenu" component (see below).
When I click on link generated from MenuLink, nothing happens. No errors, no nothing. I would expect to see "handleClick" in my console and for the link to be prevented from executing.
MenuLink.js
class MenuLink extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = props.link;
}
handleClick(e) {
console.log("handleClick");
e.preventDefault();
}
render() {
const link = this.state;
return (
<a
href={link.alias}
onClick={this.handleClick}
>
{link.title}
</a>
);
}
}
export default MenuLink;
MenuItem.js
import MenuLink from './MenuLink.js';
class MenuItem extends React.Component {
constructor(props) {
super(props);
this.state = props.item;
}
render(key) {
const item = this.state;
return(
<li
key={key}
>
<MenuLink
link={item}
/>
</li>
);
}
}
export default MenuItem;
MainMenu.js
import MenuItem from '../components/MenuItem.js';
class MainMenu extends React.Component {
state = {
menu: []
}
render() {
return(
<ul className="menu">
{this.state.menu.map(function(menuItem, i) {
return(
<MenuItem key={i} item={menuItem} />
)
})}
</ul>
);
}
componentDidMount() {
fetch('/api/menu_items/main')
.then(res => res.json())
.then((data) => {
this.setState({ menu: data })
})
.catch(console.log)
}
}
export default MainMenu;
The below snippet shows that it does work as expected. No changes were made.
class MenuLink extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = props.link;
}
handleClick(e) {
console.log("handleClick");
e.preventDefault();
}
render() {
const link = this.state;
return (
<a
href={link.alias}
onClick={this.handleClick}
>
{link.title}
</a>
);
}
}
class MenuItem extends React.Component {
constructor(props) {
super(props);
this.state = props.item;
}
render(key) {
const item = this.state;
console.log(key) // Undefined. Don't do this
return(
<li
key={key}
>
<MenuLink
link={item}
/>
</li>
);
}
}
class MainMenu extends React.Component {
state = {
menu: [{
alias: 'test',
title: 'test'
},
{
alias: 'test2',
title: 'test2'
}]
}
render() {
return(
<ul className="menu">
{this.state.menu.map(function(menuItem, i) {
return(
<MenuItem key={i} item={menuItem} />
)
})}
</ul>
);
}
}
ReactDOM.render(<MainMenu />, 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"/>
Please check this example:
import React from "react";
class MenuLink extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
// this.state = props.link;
this.state = {
link: {alias: "http://www.google.com", title: 'Google'}
}
}
handleClick(e) {
console.log("handleClick");
e.preventDefault();
}
render() {
const link = this.state.link;
return (
<div>
<a
href={link.alias}
onClick={this.handleClick}
>
{link.title}
</a>
</div>
);
}
}
export default MenuLink;
This approach should work
class MenuLink extends React.Component {
constructor(props) {
super(props);
//this.handleClick = this.handleClick.bind(this);
this.state = props.link;
}
handleClick = e => {
console.log("handleClick");
e.preventDefault();
}
render() {
const link = this.state;
return (
<a
href={link.alias}
onClick={this.handleClick}
>
{link.title}
</a>
);
}
}
export default MenuLink;
I have two child components. The first child is an image and the second child is a search input. When I type something in the input field, I want the image to hide itself. The passing of data from the second child to the parent goes well. But the first child still appears...
Parent:
class Main extends React.Component {
constructor() {
super();
this.state = {
displayValue: 'block'
};
}
hideImage = () => () => {
alert('You pressed a key, now the apple should be gone')
this.setState ({
displayValue: 'none'
});
};
render() {
return (
<div>
<Image />
<Search hideImage={this.hideImage()}/>
</div>
);
}
}
ReactDOM.render(<Main />, document.getElementById('root'));
First Child:
export default class Image extends Component {
render() {
return (
<div>
<img style={{display : this.props.displayValue}} src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcTAxoq2YSBjoS0Lo3-zfqghoyNzZ9jHxoOc5xuFBoopMtKP6n4B"></img>
</div>
)
}
}
Second Child:
export default class Search extends Component {
render() {
return (
<div>
<input onInput={this.props.hideImage} placeholder="Search someting"></input>
</div>
)
}
}
You have to pass the displayValue state into your Image component as a prop. Also you have to pass the hideImage function without initializing it using the two brackets. The below code should work for you.
class Main extends React.Component {
constructor() {
super();
this.state = {
displayValue: 'block'
};
}
hideImage = () => () => {
alert('You pressed a key, now the apple should be gone')
this.setState ({
displayValue: 'none'
});
};
render() {
return (
<div>
<Image displayValue={this.state.displayValue}/>
<Search hideImage={this.hideImage}/>
</div>
);
}
}
You just had a couple of typos.
class Image extends React.Component {
render() {
return (
<div>
<img
style={{ display: this.props.displayValue }}
src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcTAxoq2YSBjoS0Lo3-zfqghoyNzZ9jHxoOc5xuFBoopMtKP6n4B"
alt="altprop"
/>
</div>
);
}
}
// Second Child:
class Search extends React.Component {
render() {
return (
<div>
<input onInput={this.props.hideImage} placeholder="Search someting" />
</div>
);
}
}
class Main extends React.Component {
constructor() {
super();
this.state = {
displayValue: "block"
};
}
hideImage(e) {
e.preventDefault();
alert("You pressed a key, now the apple should be gone");
this.setState({
displayValue: "none"
});
};
render() {
return (
<div>
<Image displayValue={this.state.displayValue}/>
<Search hideImage={this.hideImage.bind(this)} />
</div>
);
}
}
Call your Image component like this
<Image displayValue={this.state.displayValue} />
It should then already work, but here is a shorter way to write your code.
// First Child:
const Image = ({displayValue}) => <div>
<img alt='' style={{display : displayValue}} src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcTAxoq2YSBjoS0Lo3-zfqghoyNzZ9jHxoOc5xuFBoopMtKP6n4B"></img>
</div>
I have two React Components, Gallery & Image. The Image Component uses a Gallery function as props.
Can I do the call in the render without an arrow function?
Image component:
class Image extends React.Component {
constructor(props) {
super(props);
this.state = {
filter: 'none',
};
}
render() {
return (
<div>
<button className="image-icon" onClick={() => this.props.handleClone(this.props.i)} />
</div>
);
}
}
Gallery component:
class Gallery extends React.Component {
constructor(props) {
super(props);
this.handleClone = this.handleClone.bind(this);
this.state = {
images: [],
};
}
handleClone(i) {
var newImages = this.state.images;
newImages = newImages.slice(0, i + 1).concat(newImages.slice(i));
this.setState({
images: newImages,
});
}
render() {
return (
<div>
<div className="gallery-root">
{this.state.images.map((dto, i) => {
return <Image key={'image-' + dto.id + '-' + i} i={i} handleClone={this.handleClone} />;
})}
</div>
</div>
);
}
}
Thanks.
class Image extends React.Component {
constructor(props) {
super(props);
this.state = {
filter: 'none'
};
}
handleClick = () => {
this.props.handleClone(this.props.i);
};
render() {
return (
<div>
<button className="image-icon" onClick={this.handleClick} />
</div>
);
}
}
i'm using ReactJS without FLux or Redux. I want the grand child component can communicate (read/update data) with his grandparents component.
Here's the parent component App:
export default class App extends React.Component {
static propTypes = {
children: React.PropTypes.object.isRequired
};
constructor(props) {
super(props);
this.state = {
tabActive: 0,
};
}
setTabActive(item) {
this.setState({
tabActive: item,
});
}
render() {
return (
<div>
<Header tabActive={this.state.tabActive} />
<Content>
{this.props.children}
</ Content>
<Footer />
</div>
);
}
}
child component Header:
export default class Header extends React.Component {
render() {
return (
<div>
....
<SettingTabBar tabActive={this.props.tabActive} />
</div>
);
}
}
Child of child component SettingTabBar:
export default class SettingTabBar extends React.Component {
constructor(props) {
super(props);
this.state = { activeTab: this.props.tabActive };
}
render() {
if (location.pathname.indexOf('setting') > 0) {
return (
<Tabs activeTab={this.state.activeTab} onChange={tabId => this.setState({ activeTab: tabId })} ripple>
<Tab>SETTING</Tab>
<Tab>CHARTS</Tab>
<Tab>HELP</Tab>
</Tabs>
);
}
return null;
}
}
Are there anyway to make SettingTabBar component can update data to App/Header component via function setTabActive() when onChange?
For communication with grandparent and grandchild, you can use context. It's not recomended, but it's working.
// root component
class App extends React.Component {
constructor(props){
super(props);
this.state = {
activeMenu: "none"
};
}
getChildContext() {
return {
rootCallback: menuName => {
this.setState({activeMenu: menuName});
}
}
}
render() {
return (
<div>
<div>Current active menu is: <strong>{this.state.activeMenu}</strong></div>
<Child />
</div>
);
}
}
// declare childContextTypes at context provider
App.childContextTypes = {
rootCallback: React.PropTypes.function
}
// intermediate child
class Child extends React.Component {
render() {
return (
<div>
<GrandChild />
</div>
);
}
}
// grand child
class GrandChild extends React.Component {
render() {
return (
<div>
{/* get context by using this.context */}
<button
type="button"
onClick={()=>this.context.rootCallback("one")}
>
Activate menu one
</button>
<button
type="button"
onClick={()=>this.context.rootCallback("two")}
>
Activate menu two
</button>
<button
type="button"
onClick={()=>this.context.rootCallback("three")}
>
Activate menu three
</button>
</div>
)
}
}
// also declare contextTypes at context consumer
GrandChild.contextTypes = {
rootCallback: React.PropTypes.function
}
// render it to DOM
ReactDOM.render(<App /> , document.getElementById('app-mount'));
<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>
<div id="app-mount"></div>