Transfer state from childComp to the parentComp - javascript

I have two components and i need to transfer state from children component to the parent component
class Parent Component {
this.state = {text: hahaha}
this.props.action(text, data)
<Children Component />
<button onClick={this.props.action(text, data)}
}
class Children Component {
this.state = {date: 12.12.12}
}
Another little tricky it's i have redux-action in Parent Component, that takes two parameters text and date, in sum when i click button i need to transfer state from childComp to the parentComp and then create action with two parametres in parentComp. So how i can do that?

Refer component communication
class Parent extends React.Component{
constructor(props){
super(props);
this.state = {
content: 'initial'
}
this.updateParentState = this.updateParentState.bind(this);
}
updateParentState(content){
this.setState({
content: content
})
}
render(){
let { content } = this.state;
return <div>
<Child updateParentState={this.updateParentState}/>
<h1>{ content }</h1>
</div>
}
}
class Child extends React.Component{
constructor(props){
super(props);
this.state = {
value: 'initial'
}
this.handleParentState = this.handleParentState.bind(this);
this.changeContent = this.changeContent.bind(this);
}
handleParentState(content){
let { updateParentState } = this.props;
let { value } = this.state;
updateParentState(content);
}
changeContent(event){
this.setState({
value: event.target.value
})
}
render(){
let { value } = this.state
return <div>
<input value={value} onChange={this.changeContent}/>
<button onClick={this.handleParentState}>Update Parent State</button>
</div>
}
}

You can get state of child in parent component wil call back:
class Parent extends React.Component{
constructor(){
super();
this.state = {
};
}
onClick(childState){
console.log(childState); //see child state in parent component
}
render(){
return <Child onClick={this.onClick} />;
}
}
class Child extends React.Component{
constructor(){
super();
this.state = {
first: "first",
second: "second"
};
}
render(){
return <div onClick={() => this.props.onClick({...this.state})}>Click me</div>;
}
}
Also You can use redux or ref.

Related

Why isn't React re-rendering the page after the state is changed?

so I was working on a basic Todo app using React.js and I was wondering why the todo component does not automatically re-render once the state changed (the state contains the list of todos- so adding a new todo would update this array)? It is supposed to re-render the Header and the Todo component of the page with the updated array of todos passed in as props. Here is my code:
import React from 'react';
import './App.css';
class Header extends React.Component {
render() {
let numTodos = this.props.todos.length;
return <h1>{`You have ${numTodos} todos`}</h1>
}
}
class Todos extends React.Component {
render() {
return (
<ul>
{
this.props.todos.map((todo, index) => {
return (<Todo index={index} todo={todo} />)
})
}
</ul>
)
}
}
class Todo extends React.Component {
render() {
return <li key={this.props.index}>{this.props.todo}</li>
}
}
class Form extends React.Component {
constructor(props) {
super(props);
this.addnewTodo = this.addnewTodo.bind(this);
}
addnewTodo = () => {
let inputBox = document.getElementById("input-box");
if (inputBox.value === '') {
return;
}
this.props.handleAdd(inputBox.value);
}
render() {
return (
<div>
<input id="input-box" type="text"></input>
<button type="submit" onClick={this.addnewTodo}>Add</button>
</div>
)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = { todos: ['task 1', 'task 2', 'task 3']}
this.handleNewTodo = this.handleNewTodo.bind(this);
}
handleNewTodo(todo) {
let tempList = this.state.todos;
tempList.push(todo);
this.setState = { todos: tempList };
}
render() {
return (
<div>
<Header todos={this.state.todos} />
<Todos todos={this.state.todos} />
<Form todos={this.state.todos} handleAdd={this.handleNewTodo} />
</div>
)
}
}
You are not updating the state correctly.
You need to make a copy of the this.state.todos, add the new todo in the copied array and then call this.setState function
handleNewTodo(todo) {
let tempList = [...this.state.todos];
tempList.push(todo);
this.setState({ todos: tempList });
}
Notice that this.setState is a function
You're updating state incorrectly,
handleNewTodo(todo) {
let tempList = [...this.state.todos];
tempList.push(todo);
this.setState({ todos: tempList });
}
This is the correct syntax.

Can a child method have change handler in React?

I was wondering why the child component with the changed value is not getting rendered here.
Isn't it a good idea to have a child handle its own changes or better to have the controller in the parent?
class App extends React.Component {
constructor() {
super();
this.state = {
todos: todosData
};
}
render() {
const todoItems = this.state.todos.map(item => (
<TodoItem key={item.id} item={item} />
));
return <div className="todo-list">{todoItems}</div>;
}
}
This is the Child TodoItem
class TodoItem extends React.Component {
constructor(props) {
super(props);
this.state = {
isComp: {}
};
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
let tempObj = this.state.isComp;
tempObj.completed = !this.state.isComp.completed;
this.setState = { isComp: tempObj };
console.log(this.state.isComp);
}
render() {
this.state.isComp = this.props.item;
console.log(this.state.isComp);
return (
<div className="todo-item">
<input type="checkbox" checked={this.state.isComp.completed} />
<p>{this.props.item.text}</p>
</div>
);
}
}
As you can see the state is changed with handleChange() but this does not fire the render. I am also not too sure if another object can be assigned to an object of the state (let tempObj = thi.state.isComp).
The functionality I am trying to achieve is check and uncheck a box and render accordingly.
What is this?
this.setState = { isComp: tempObj };
I think it should be
this.setState({ isComp: tempObj });

React JS : grandparent component's setState method doesn't update state of a grandchild input field onChange event click

In the same code, I was able to the get the grandparent component's setState method to update accordingly for an onClick event from the grandchild component, however, for the onChange event, it is failing. I am not getting any errors.
class GrandChild extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
changeNumber=()=> {
this.props.changeNumber();//call child method
}
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
const data = this.props.data;
return(
<div>
<h1>The number is {this.props.number}</h1>
<input type="text" value = {data} onChange={this.handleChange} />
<button onClick={this.changeNumber}>Increase number by 1</button>
</div>
)
}
}
class Child extends React.Component {
render() {
return(
<div>
<GrandChild number={this.props.number} changeNumber={this.props.changeNumber} value={this.props.data} onChange={this.props.handleChange}/>
</div>
)
}
}
class App extends React.Component {
constructor() {
super()
this.state = {
number: 1,
data: ""
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(data) {
this.setState({data:this.state.data});
console.log(data);
}
changeNumber=()=>{
this.setState((prevState)=>{
console.log(prevState,this.state.data);
return {
number : prevState.number + 1
}
});
}
render() {
const data = this.state.data;
const input = data;
return (
<Child number={this.state.number}
changeNumber = {this.changeNumber}
data={input}
onChange = {this.handleChange}
/>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Console Result:
Object {
data: "",
number: 1
} ""
result screenshot:
console.log result
see code pen for live code:
https://codepen.io/codehorse/pen/yLyEwBw?editors=0011
Your improved code with live demo https://codesandbox.io/s/laughing-sky-kk97b
What need to change <GrandChild number={this.props.number} changeNumber={this.props.changeNumber} value={this.props.data} onChange={this.props.onChange}/>
Complete Code
class GrandChild extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
changeNumber = () => {
this.props.changeNumber(); //call child method
};
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
const data = this.props.data;
return (
<div>
<h1>The number is {this.props.number}</h1>
<input type="text" value={data} onChange={this.props.onChange} />
<button onClick={this.changeNumber}>Increase number by 1</button>
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
<GrandChild
number={this.props.number}
changeNumber={this.props.changeNumber}
value={this.props.data}
onChange={this.props.onChange}
/>
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 1,
data: ""
};
}
handleChange = e => {
this.setState({ data: e.target.value });
console.log(e.target.value);
};
changeNumber = () => {
this.setState(prevState => {
console.log(prevState, this.state.data);
return {
number: prevState.number + 1
};
});
};
render() {
const data = this.state.data;
const input = data;
return (
<Child
number={this.state.number}
changeNumber={this.changeNumber}
data={input}
onChange={this.handleChange}
/>
);
}
}
export default App;

React Handle interaction state between components

I have a simple component who show element onClick:
class MyComponent extends React.Component {
state = {
isVisible : false
}
render() {
const { isVisble } = this.state
return(
<div>
{isVisble ?
<div onClick={() => this.setState({isVisble: false})}>Hide</div> :
<div onClick={() => this.setState({isVisble: true})}>Show</div>}
</div>
)
}
}
I use this component three times in other component :
class MySuperComponent extends React.Component {
render() {
return(
<div>
<MyComponent />
<MyComponent />
<MyComponent />
</div>
)}
}
I need to pass isVisible at false for all other component if one of have isVisible to true
How to do that ?
Thanks
You should have your component controlled, so move isVisble to props and and then assign it from MySuperComponent.
Also pass MyComponent a callback so it can inform the parent if it wants to change the state.
You'd want some data structure to store that states.
https://codepen.io/mazhuravlev/pen/qxRGzE
class MySuperComponent extends React.Component {
constructor(props) {
super(props);
this.state = {children: [true, true, true]};
this.toggle = this.toggle.bind(this);
}
render() {
return (
<div>
{this.state.children.map((v, i) => <MyComponent visible={v} toggle={() => this.toggle(i)}/>)}
</div>
)
}
toggle(index) {
this.setState({children: this.state.children.map((v, i) => i !== index)});
}
}
class MyComponent extends React.Component {
render() {
const text = this.props.visible ? 'visible' : 'hidden';
return (<div onClick={this.props.toggle}>{text}</div>);
}
}
React.render(<MySuperComponent/>, document.getElementById('app'));
You can check your code here, is this what you want.
example

React.js: Why child component change parent state?

Why in this example child component changing parent component state? According to the Facebook(react.js) docs State is similar to props, but it is private and fully controlled by the component.
codepen example
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {data: this.props.data};
}
handleChange(event) {
let updatedData = Object.assign({}, this.state.data);
updatedData[event.target.name][event.target.dataset.lang] = event.target.value;
this.setState({
data: updatedData
});
}
render() {
return (
<form>
{Object.keys(this.props.data.titles).map((l, index) =>
<input type="text" name="titles" data-lang={l} value={this.state.data.titles[l]} onChange={this.handleChange.bind(this)} />
)}
</form>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
images: [{"titles": {"en": "deluxe1500x930.jpg"}
}],
count: 1
};
}
render() {
return (
<div>
{Object.keys(this.state.images).map((x,index) =>
<div>
{this.state.images[x].titles.en}
<NameForm data={this.state.images[x]} />
<button onClick={(() => {this.setState({ count: 2 })}).bind(this)}>test</button>
</div>
)}
</div>
)
}
}
Because you set the state with this.props.data.
the this.props.data came from the parent, therefore when it's changing so the state changes as well.
The solution is simple, just set the state with new value (copied from this.props.data) by using the spread operator instead of using the same reference.
this.state = {data: ...this.props.data};

Categories