Class based app here.
MainComponent.js
export class MainComponent extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
nr: 0
}
}
btnClicked(e, nr, name){
this.setState({name: name});
this.setState({nr: nr});
}
render() {
return (
<div>
<div>
<button className="btn btn-success" onClick={e => this.btnClicked(e, '1', 'one')}>UNO</button>
<button className="btn btn-success" onClick={e => this.btnClicked(e, '2', 'two')}>DUE</button>
<button className="btn btn-success" onClick={e => this.btnClicked(e, '1', 'three')}>TRE</button>
</div>
<div>
{this.state.nr === '1' && <Child1 name={this.state.name}/>}
{this.state.nr === '2' && <Child2 name={this.state.name}/>}
</div>
</div>
)
}
}
export default MainComponent;
And then here are the 2 child-components:
Child1.js
export class Child1 extends Component {
constructor(props) {
super(props);
this.state = {
name: props.name,
}
}
render() {
return (
<div>
<div>
{
this.state.name !== '' &&
<h3>{this.state.name}</h3>
}
</div>
</div>
)
}
}
export default Child1;
Child2.js
export class Child2 extends Component {
constructor(props) {
super(props);
this.state = {
name: props.name,
}
}
render() {
return (
<div>
<div>
{
this.state.name !== '' &&
<h3>{this.state.name}</h3>
}
</div>
</div>
)
}
}
export default Child2;
When I click to the button "One" I see the text "One". But when clicking on button "Three" I still see the same text "One".
I have tried adding forceUpdate but it didnt help:
btnClicked(e, nr, name){
this.forceUpdate(function(){
this.setState({name: name});
this.setState({nr: nr});
});
}
How can I instruct the app to rerender the child component at each click?
In this case you should not assign the Child components prop value to state. Just use the prop value in the component.
export class Child1 extends Component {
render() {
return (
<div>
<div>
{
this.props.name !== '' &&
<h3>{this.props.name}</h3>
}
</div>
</div>
)
}
}
export default Child1;
The Child component's constructor will not be called each time the props update. So, state will not be updated when the props are updated.
In this case - as in most cases - you do not need forceUpdate.
Related
//child component
import React, { Component } from 'react'
const NavButton = ({ active, title, href, onSetActive }) => {
return (
<button
className={active ? "btn btn-light regular-btn active" : "btn btn-light regular-btn"}
href={href}
onClick={onSetActive} >
{title}
</button>
)
}
class Child extends Component {
constructor(props) {
super(props);
this.state = {
activeIndex: 1,
buttons: [
{
title: "1",
key: 0,
value: 1
},
{
title: "3",
key: 1,
value: 3
}
]
}
}
//It was changing active index
handleChangeActive(newActiveIndex) {
// console.log("Working");
this.setState({ activeIndex: newActiveIndex });
}
render() {
const { activeIndex } = this.state;
return (
<div>
<nav id="navbarMain">
<div className="navbar-nav flex-row">
{this.state.buttons.map((button, buttonIndex) =>
/* determine which nav button is active depending on the activeIndex state */
<NavButton onClick={() => this.investmentHandler.bind(this)} value={button.value} onSetActive={() => this.handleChangeActive(buttonIndex)} active={buttonIndex === activeIndex} title={button.title} key={button.key} />)}
</div>
</nav>
</div>
)
}
}
export default Child
// parent component
import React, { Component } from 'react'
import Child from './Child';
class Parent extends Component {
constructor(props) {
super(props)
this.state = {
firstValue: 1,
secondValue: 3,
result: ''
}
// this.add = this.add.bind(this);
}
//calculating the input values
Add = () => {
var { firstValue, secondValue, result } = this.state;
result = firstValue + secondValue;
console.log(result);
document.getElementById("result").innerHTML = result;
}
render() {
return (
<>
//Child component is used inside the parent component using props
<Child investmentHandler={this.add} />
<p id="result">Result</p>
</>
)
}
}
export default Parent
I need the event handler(Add) has to work inside the child component.
How to use event handler using props in class components.
How to call the parent Method in child class component in react.
I was tried using props but it was not working.
Based on the child component input button it has to get the result.
On Child class your component NavButton has an onClick attribute that calls onSetActive, so you can call investmentHandler on the onSetActive function:
//child component
import React, { Component } from "react";
const NavButton = ({ active, title, href, onSetActive }) => {
return (
<button
className={
active
? "btn btn-light regular-btn active"
: "btn btn-light regular-btn"
}
href={href}
onClick={onSetActive}
>
{title}
</button>
);
};
class Child extends Component {
constructor(props) {
super(props);
this.state = {
activeIndex: 1,
buttons: [
{
title: "1",
key: 0,
value: 1,
},
{
title: "3",
key: 1,
value: 3,
},
],
};
}
//It was changing active index
handleChangeActive(newActiveIndex) {
// console.log("Working");
this.setState({ activeIndex: newActiveIndex });
this.props.investmentHandler();
}
render() {
const { activeIndex } = this.state;
return (
<div>
<nav id="navbarMain">
<div className="navbar-nav flex-row">
{this.state.buttons.map((button, buttonIndex) => (
/* determine which nav button is active depending on the activeIndex state */
<NavButton
value={button.value}
onSetActive={() => this.handleChangeActive(buttonIndex)}
active={buttonIndex === activeIndex}
title={button.title}
key={button.key}
/>
))}
</div>
</nav>
</div>
);
}
}
export default Child;
On the Parent class when getting the props from the Child class you was calling "this.add" when you should be calling "this.Add":
// parent component
import React, { Component } from 'react'
import Child from './Child';
class Parent extends Component {
constructor(props) {
super(props)
this.state = {
firstValue: 1,
secondValue: 3,
result: ''
}
// this.add = this.add.bind(this);
}
//calculating the input values
Add = () => {
console.log('Im here')
var { firstValue, secondValue, result } = this.state;
result = firstValue + secondValue;
console.log(result);
document.getElementById("result").innerHTML = result;
}
render() {
return (
<>
<Child investmentHandler={this.Add} />
<p id="result">Result</p>
</>
)
}
}
export default Parent
I made this few changes and the code worked for me.
Check this might help
//child component
import React, { Component } from 'react'
const NavButton = ({ active, title, href, onSetActive }) => {
return (
<button
className={active ? "btn btn-light regular-btn active" : "btn btn-light regular-btn"}
href={href}
onClick={onSetActive} >
{title}
</button>
)
}
class Child extends Component {
constructor(props) {
super(props);
this.state = {
activeIndex: 1,
buttons: [
{
title: "1",
key: 0,
value: 1
},
{
title: "3",
key: 1,
value: 3
}
]
}
}
//It was changing active index
handleChangeActive(newActiveIndex) {
// console.log("Working");
this.setState({ activeIndex: newActiveIndex });
}
render() {
const { activeIndex } = this.state;
return (
<div>
<nav id="navbarMain">
<div className="navbar-nav flex-row">
{this.state.buttons.map((button, buttonIndex) =>
/* determine which nav button is active depending on the activeIndex state */
<NavButton onClick={() => this.props.investmentHandler()} value={button.value} onSetActive={() => this.handleChangeActive(buttonIndex)} active={buttonIndex === activeIndex} title={button.title} key={button.key} />)}
</div>
</nav>
</div>
)
}
}
export default Child
// parent component
import React, { Component } from 'react'
import Child from './Child';
class Parent extends Component {
constructor(props) {
super(props)
this.state = {
firstValue: 1,
secondValue: 3,
result: ''
}
// this.add = this.add.bind(this);
}
//calculating the input values
Add = () => {
var { firstValue, secondValue, result } = this.state;
result = firstValue + secondValue;
console.log(result);
document.getElementById("result").innerHTML = result;
}
render() {
return (
<>
//Child component is used inside the parent component using props
<Child investmentHandler={this.Add} />
<p id="result">Result</p>
</>
)
}
}
export default Parent
I have a Tabbar in my Tabbar Component, Which I Change the index props in it :
class Tabbar extends Component {
state = {
index: this.props.index,
name: this.props.name,
image: this.props.image
};
changeTabs = () => {
this.setState({index: this.props.index});
}
render() {
return (
<React.Fragment>
<div id={this.state.index} className="col">
<button onClick={this.changeTabs}></button>
</div>
</React.Fragment>
);
}
}
export default Tabbar;
And Then In my Other Component, I Wanna Re-Render a fragment after props change. Here's my Code :
import Tabbar from './Tabbar';
class Tabview extends Component {
constructor(props) {
super(props);
this.state = {
tabs: [
{index: 0, name: "tab0", image:require('../Assets/profile.svg'),childView: {ProfilePage} },
{index: 1, name: "tab1", image:require('../Assets/home.svg'),childView: {HomePage}},
{index: 2, name: "tab2", image:require('../Assets/blog.svg'),childView: {BlogPage}},
],
}
}
handleRender = () => {
this.state.tabs.map(item => {
if (item.index === this.props.index) {
return <item.childView/>;
}
})
return <BlogPage/>;
}
render() {
return (
<div>
<Header/>
{this.handleRender()}
{this.state.tabs.map(item =>
<Tabbar key={item.index} index={item.index} name={item.name} image={item.image}/>
)}
</div>
);
}
}
export default Tabview;
The Method "handleRender" should handle the rendering.
I tried to use "componentDidMount" or "componentDidUpdate", But I didn't work.
How Can I Make it Work?
Thank you in advance!
You dont need to have a state in the child component for this reason
You can simply have a callback in parent and call it in child component like below.
import React, { Component } from "react";
class Tabbar extends Component {
render() {
return (
<React.Fragment>
<div id={this.props.index} className="col">
<button
onClick={() => this.props.changeTabs(this.props.index)}
></button>
</div>
</React.Fragment>
);
}
}
export default Tabbar;
And in parent you maintain the active index state
import Tabbar from "./Tabbar";
import React, { Component } from "react";
class Tabview extends Component {
constructor(props) {
super(props);
this.state = {
tabs: [
//your tabs
],
activeIndex: 0
};
}
handleRender = () => {
this.state.tabs.map((item) => {
if (item.index === this.state.activeIndex) {
return <item.childView />;
}
});
return <div />;
};
render() {
return (
<div>
{this.handleRender()}
{this.state.tabs.map((item) => (
<Tabbar
key={item.index}
index={item.index}
name={item.name}
image={item.image}
changeTabs={(index) => this.setState({ activeIndex: index })}
/>
))}
</div>
);
}
}
export default Tabview;
I am making a Todo App in React JS, i'm fairly new to React JS.
I have made two components named AddComponent and TodoItem component. The AddComponent has an input and button to add the todos and it will render TodoItem as a child component whenever a todo is added using the AddComponent.
I also have to remove the child component TodoItem when a button inside it is clicked according to it's key, so it would remove that item from the state of the parent component AddComponent.
The problem i'm facing is i can't change the state anywhere else than the render() function, because there is where i'm dynamically generating the TodoItem components using the state.
And changing the state inside the render() function would result in an infinite loop. Please help how to resolve this problem.
I'm using Bootstrap 4 using a CDN for styling.
AddComponent.js
import React from 'react'
import shortid from 'shortid'
import TodoItem from './TodoItem';
class AddComponent extends React.Component {
constructor() {
super();
this.state = {
todoText: '',
todoList: []
}
this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleTodoClick = this.handleTodoClick.bind(this);
}
handleChange(e) {
e.persist();
this.setState((prevState) => {
return {
todoText: e.target.value,
todoList: prevState.todoList
}
})
}
handleClick() {
this.setState((prevState) => {
return {
todoText: prevState.todoText,
todoList: [{
text: prevState.todoText,
id: shortid.generate()
}, ...prevState.todoList]
}
})
}
handleTodoClick(id) {
const newState = this.state.todoList.filter(todoL => todoL.id === id);
this.setState({ todoList: newState });
}
render() {
const todos = this.state.todoList.map((todo) => {
return (
<TodoItem key={todo.id} value={todo.text} click={this.handleTodoClick(todo.id)}>{todo.text}</TodoItem>
)
})
return (
<div>
<div className="row">
<div className="col-sm-9">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Add a Todo"
onChange={this.handleChange}
/>
</div>
</div>
<div className="col-sm-3">
<button
type="button"
className="btn btn-primary btn-block"
onClick={this.handleClick}
>Add
</button>
</div>
</div>
<div>
{todos}
</div>
</div>
)
}
}
export default AddComponent
TodoItem.js
import React from 'react'
class TodoItem extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="alert alert-secondary alert-dismissible fade show">
<button
type="button"
className="close"
onClick={this.props.click}
data-dismiss="alert">×</button>
{this.props.value}
</div>
)
}
}
export default TodoItem
Try : https://codesandbox.io/s/hopeful-moon-duqfe
There were two problems; 1st one is filter and the 2nd one is handler callback function that is set to click prop.
1st problem : Filter function should filter that does not match your id so you should use NOT equal :
handleTodoClick(id) {
const newState = this.state.todoList.filter(todoL => todoL.id !== id);
this.setState({ todoList: newState });
}
2nd problem : When you set click prop as a handler callback function, you should set reference of the function itself without calling it. Not like this : click={this.handleTodoClick(todo.id). This will call the function and set the click prop to result of it, which is undefined since it does not return to anything.
So i have changed your click props as click={this.handleTodoClick}
const todos = this.state.todoList.map(todo => {
return (
<TodoItem key={todo.id} id={todo.id} value={todo.text} click={this.handleTodoClick}>
{todo.text}
</TodoItem>
);
});
On child component, onClick is similary set to function itself onClick={() => this.props.click(this.props.id)} NOT like onClick={this.props.click(this.props.id)}.
import React from "react";
class TodoItem extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="alert alert-secondary alert-dismissible fade show">
<button
type="button"
className="close"
onClick={() => this.props.click(this.props.id)}
data-dismiss="alert"
>
×
</button>
{this.props.value}
</div>
);
}
}
Fix:
<TodoItem key={todo.id} todoId={todo.id} value={todo.text} click={this.handleTodoClick(todo.id)}>{todo.text}</TodoItem>
We can't use key as id. The key property is used by React under the hood, and is not exposed to us.
import React from 'react'
class TodoItem extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="alert alert-secondary alert-dismissible fade show">
<button
type="button"
className="close"
// look here
onClick={e => {this.props.click(this.props.todoId)}}
data-dismiss="alert">×</button>
{this.props.value}
</div>
)
}
}
export default TodoItem
Try the following by updating the handle for click in AddComponent then creating a handler within TodoItem that calls props click with the respective todo item id value. I'd recommend to just pass the entire todo so that you can access both the unique id and value in TodoItem:
AddComponent:
const todos = this.state.todoList.map((todo) => {
return (
<TodoItem key={todo.id} todo={todo} click={this.handleTodoClick}>{todo.text}</TodoItem>
)
})
TodoItem:
import React from 'react'
class TodoItem extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.click(this.props.todo.id);
}
render() {
return (
<div className="alert alert-secondary alert-dismissible fade show">
<button
type="button"
className="close"
onClick={this.handleClick}
data-dismiss="alert">×</button>
{this.props.todo.value}
</div>
)
}
}
export default TodoItem;
I want to toggleclass name of one element by clicking on another element. Both elements are in separate component files. I don't know how to get the state of an element and pass it to another element. Please help me solving the problem.
file1.js
<Button onClick={this.toggleFunction}>Button</Button>
file2.js
<div class="wrapper"></div>
I want to toggle class active on wrapper div when the button is clicked.
Thanks
class MyComponent extends Component {
constructor(props) {
super(props);
this.addActiveClass= this.addActiveClass.bind(this);
this.state = {
active: false,
};
}
toggleClass() {
const currentState = this.state.active;
this.setState({ active: !currentState });
};
render() {
return (
<div
className={this.state.active ? 'your_className': null}
onClick={this.toggleClass}
>
<p>{this.props.text}</p>
</div>
)
}
}
Parent Component
import React from "react";
import ButtonComponent from "./buttonComponent";
import "./demo.css";
//Parent Component
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
active: false
};
}
updateValue = value => {
this.setState({
active: value
});
};
render() {
return (
<div>
<ButtonComponent updateParent={this.updateValue} />
<div
className={
this.state.active ? "dropdownbutton1" : "dropdownbutton1Active"
}
>
<label>First</label>
<br />
<select>
<option value="yes">yes</option>
<option value="no">no</option>
</select>
</div>
</div>
);
}
}
export default Demo;
Child Component
import React from "react";
import ToggleButton from "react-toggle-button";
import "./demo.css";
class ButtonComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
active: false,
defaultValue: 1
};
}
togglebutton = () => {
this.props.updateParent(this.state.active);
this.setState({ active: !this.state.active });
if (this.state.active) {
this.setState({ defaultValue: 1 });
} else {
this.setState({ defaultValue: -1 });
}
};
render() {
return (
<div>
<div className="ToggleButton">
<ToggleButton onClick={this.togglebutton} value={this.state.active} />
</div>
</div>
);
}
}
export default ButtonComponent;
Link :https://codesandbox.io/s/m4py2y97zp
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>