componentWillReceiveProps not being called - javascript

I'am updating the state messages and id of TalkContent and I'am trying to pass it to the appropriate child of Talks (which is itself a child of TalkContent).
TalkContent
class TalkContent extends React.Component{
constructor(props){
super(props)
this.state = { talks : [], id : -1, messages : []};
//
}
render(){
if (this.state.id === -1)
{
return(
<div className="TalksList">
<Talks talks={this.state.talks} onTalkClick={this.onTalkClick} messages={this.state.messages} talkId={this.state.id} />
//
</div>
)
}
Talks
class Talks extends React.Component{
render(){
const talks = this.props.talks.map((talk, i) => {
return (
<Talk
key={i}
id={i}
talk={talk.talk}
username={talk.username}
date={talk.date}
onTalkClick={this.props.onTalkClick}
messages={this.props.messages}
talkId={this.props.talkId}
/>
)
});
return(
<div className="talkList">
{talks}
</div>
)
} //render
}
Talk
class Talk extends React.Component{
constructor(props){
super(props);
this.state = { messages : []};
this.handleClick = this.handleClick.bind(this);
}
render(){
return(
<div>
{this.props.username} : <span onClick={this.handleClick}>{this.props.talk}</span> {moment(this.props.date).fromNow()}
</div>
)
}
componentWillReceiveProps(nextProps) {
if(this.props.id === this.nextProps.talkId){
this.setState({messages: nextProps.messages});
}
}
However, even when the states messages and id of TalkContent (the parent component) are updated, the function componentWillReceiveProps of Talk is never fired, in any of the childs. Can someone tell me what is wrong please?

I've quickly made a code sandbox that shows how a parent component can talk to a child component. If you open up Developer Tools > Console, you can see the props updating from both Parent and Child component. Hope it helps and feel free to ask any questions.
Example for Mit

According to the discussion. It seems props values were changed in the parent level(TalkContent Component) and props change was expected to fire in the Grand Child Component (Talk Component) through componentWillReceiveProps function.
componentWillReceiveProps gets normally fired within the child component if the props are changed in the parent component. So make-sure implementing componentWillReceiveProps function should happen within parent-child hierarchy only

React doesn't automatically rerender the component Talks if this.props are changed, you need to manually trigger a rerender using this.forceUpdate() or by setting state on it and updating that.

Related

Reactjs : How to change props data from parent component that already distribute to child component?

I just creating a project and use a several component for a page and pass data by using props to each components. The problem is, when I have already change data from parent component to child component by using props and I have update the data from parent component, the child component still using the old data.
The example is just like this:
class Child extends Component{
constructor(props){
super(props);
this.state = {
variabel : props.variable
}
}
render() {
return (
<div>
<h1>{this.state.variable}</h1>
</div>
)
}
}
class Parent extends Component{
constructor(props){
super(props);
this.state = {
variabel : 'Hello'
}
}
render() {
return (
<div>
<Child variable={this.state.variable} />
</div>
)
}
}
So, when I run the page and update the variabel state in Parent Component, Child Component still show the old value. How to make it updated as the Parent Component data? Or I must using Redux for this case?
In general you'll only want to keep one particular piece of state in one place. If you reassign it in the constructor of Child, it will not update when the parent's state updates. So something like this pattern should work:
class Child extends Component{
// Note that no constructor is needed as you are not initializing any state or binding any methods.
render() {
return (
<div>
<h1>{this.props.variable}</h1>
</div>
)
}
}
class Parent extends Component{
constructor(props){
super(props);
this.state = {
variable : 'Hello'
}
}
render() {
return (
<div>
<Child variable={this.state.variable} />
</div>
)
}
}
A warning note about not initializing state with props is in the React docs for constructor, as a matter of fact.
Mitch Lillie's answer is the correct one. You should have only one source of truth.
In general, it's a good idea to keep the state in the nearest common ancestor of the components that depend on the state. Then you pass the props down.
If, however, you need to keep a copy of the prop in the child state, you should use the life cycles that React provides.
Codepen Live Demo
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
variable: props.variable,
};
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.props.variable !== prevState.variable) {
this.setState({
variable: this.props.variable,
});
}
}
render() {
const varState = this.state.variable;
const varProps = this.props.variable;
return (
<div>
Child props: {varProps}
<br />
Child state: {varState}
</div>
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
setInterval(this.updateTime, 1000); // refresh every second
this.state = {
variable: new Date().toLocaleString(),
};
}
updateTime = () => {
this.setState({
variable: new Date().toLocaleString(),
});
}
render() {
const time = this.state.variable;
return (
<div>
<div>
Parent: {time}
</div>
<Child variable={time} />
</div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('container')
);

Can child component only change parent state if event is triggered?

I'm trying to understand how a child component can change its parents' state and realize that the only examples in which I am able to successfully accomplish this (and the only examples I see online) deal with a callback being passed from a parent to a child that is then linked to an event (onClick, onChange etc..) in the child. Thus, can a child component only change it's parents' state if the child uses an event to call the inherited callback?
This works:
class Child extends React.Component{
handleClick(){
console.log('pressed')
this.props.message('Hi mom!')
}
render(){
return (<button onClick={this.handleClick.bind(this)}>Prese Me</button>)
}
};
class Parent extends React.Component {
constructor(props){
super(props)
this.state = {
messageFromChild: '',
}
this.callBackFromParent = this.callBackFromParent.bind(this);
}
callBackFromParent(dataFromChild){
this.setState({messageFromChild: dataFromChild})
}
render(){
return (
<div>
<h2>Message from Child is:</h2>
<h2>{this.state.messageFromChild}</h2>
<Child message={this.callBackFromParent}/>
</div>
)
}
}
But this leads to in infinite loop:
class Child extends React.Component{
render(){
this.props.message('Hi Mom')
return(
<h2>Dummy message from child</h2>
)
}
};
class Parent extends React.Component {
constructor(props){
super(props)
this.state = {
messageFromChild: '',
}
this.callBackFromParent = this.callBackFromParent.bind(this);
}
callBackFromParent(dataFromChild){
this.setState({messageFromChild: dataFromChild})
}
render(){
return (
<div>
<h2>Message from Child is:</h2>
<h2>{this.state.messageFromChild}</h2>
<Child message={this.callBackFromParent}/>
</div>
)
}
}
You don't necessarily need to use the functions as event handlers, but calling it directly on render would cause the parent component to setState immediately, which would result in another render of the Child component, and the loop continues. You could e.g. set a timeout in componentDidMount of the Child and it will work fine.

State value not updating reactjs

class RaisablePaper extends Component {
constructor(props) {
super();
this.state = {
state1: "state1",
openNow: props.boxOpen,
};
}
}
I am trying to send value to this class by doing <RaisablePaper boxOpen={this.state.dOpen}/>. But whenever the dOpen gets changed it does not seem to update the openNow. Help would very much appreciated.
You are setting the state before mounting the component in the constructor, which will not be fired again when the props change. For that you can use React's componentWillReceiveProps, which will be called when new props are sent to the component.
class RaisablePaper extends Component {
constructor(props) {
super();
this.state = {
state1: "state1",
openNow: props.boxOpen
};
}
componentWillReceiveProps(props) {
this.setState({
openNow: props.boxOpen
});
}
}
It would be simpler to use the props directly instead of worrying about syncing it to your state. It's a good idea in general to rely on props as much as possible, and only involve state when absolutely necessary.
But Fabian Schultz is absolutely right -- your constructor only runs once, before the component is mounted, so you'll never receive the subsequent updates if the component is relying on state which is initialized during construction.
I'm just imagining how you're using the boxOpen state to show an example; you can follow the same general idea with whatever your render method is doing.
class RaisablePaper extends Component {
render() {
return (
<div className={this.props.boxOpen ? 'is-open' : ''}>
Here's some content...
</div>
);
}
}

Letting a child know that it should update its state in React

I'm trying to let a child Component know that it should update its state after a prop change in the parent.
There is no state that needs to be shared between the two. The only thing that needs to happen is that the parent should somehow let the child know that it needs to update its state (literally call setState by itself with the info it already has).
So far I can only figure out to do in the "React"-way through the componentWillReceiveProps and sending some arbitrary props, like a number, to let the child know that it should call the function to set the state.
Another way would be to use signals to let the child know, but this seems a bit over the top for this situation.
So in summary:
The parent needs to let the child know that it should call a function
The function will update the state (setState) of the child
There is no need for the child to receive any information from the parent
Can anyone help me figure out the best way to do this?
As you can see in the snippet, this is more or less the situation. I would like to know the best way to have the Child component call the _updateState function when the Parents props have changed (does not happen in the snippet right now).
//Imagine this is the redux-container that passes the store state to the parent.
class ParentWrapper extends React.Component {
constructor(){
super();
this.state = {status: 'normal'};
}
//This would be an action to the reducer that would update the store state
_updateStatus(){
this.setState({status: 'updated'});
}
render(){
return (
<div>
<button onClick={this._updateStatus.bind(this)}>Click me</button>
<Parent status={this.state.status} />
</div>
);
}
}
class Parent extends React.Component {
render(){
return (
<div>
<Child />
</div>
);
}
}
Parent.propTypes = {
status: React.PropTypes.string
};
Parent.defaultProps = {
status: 'normal'
};
class Child extends React.Component {
constructor(){
super();
this.state = { test: 1 };
}
_updateState(){
this.setState({test: this.state.test + 1});
}
render(){
return (
<div>Child: {this.state.test}</div>
);
}
}
ReactDOM.render(<ParentWrapper />, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react-dom.min.js"></script>
<div id="container"></div>
EDIT: added snippet.
You can use refs to access all the methods under the child component.
See the following fiddle
https://jsfiddle.net/pranesh_ravi/412j5ucw/
Here using refs, I'm calling a function inside the child which will change the state of the child component.

Reactjs:Is it possible to use Parent component property from another Parent's child component

I have a file named separatefile.jsx, in this file parent component name is Content and child component name is Child.
separatefile.jsx
import React from 'react';
import Parent from './learning.jsx';
class Content extends React.Component {
constructor() {
super();
this.state = {
finding : 'i am finding'
}
}
render() {
return (
<div>
<Child childprop={this.state.finding}/>
<Parent/>
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
<h2>{this.props.childprop}</h2>
<h1>child class property</h1>
</div>
);
}
}
export default Content;
This is another file named as learning.jsx , this file has Parent component named as Parent and Child component named as a Children.
My questions is that i need to access Parent component property(parent component for learning.jsx) from Child component(child component for separatefile.jsx file)...
learning.jsx
import React from 'react';
class Parent extends React.Component {
constructor() {
super();
this.state = {
searching : 'i will find the solution'
}
}
render() {
return (
<div>
<Children childrenprop={this.state.searching}/>
</div>
);
}
}
class Children extends React.Component {
render() {
return (
<div>
<h2>{this.props.childrenprop}</h2>
</div>
);
}
}
export default Parent;
If I understood you correctly, you want to use Parent's state in your Children component?
You can pass it down the component tree as props, e.g.:
class Content extends React.Component {
constructor() {
super();
this.state = {
finding : 'i am finding'
}
}
render() {
return (
<div>
<Child childprop={this.state.finding}/>
<Parent finding={this.state.finding} />
</div>
);
}
}
class Parent extends React.Component {
constructor() {
super();
this.state = {
searching : 'i will find the solution'
}
}
render() {
return (
<div>
<Children finding={this.props.finding} childrenprop={this.state.searching}/>
</div>
);
}
}
class Children extends React.Component {
render() {
return (
<div>
<h2>{this.props.childrenprop}</h2>
<div>{this.props.finding}</div>
</div>
);
}
}
It's probably not a direct answer but if you are starting a new app I would recommend you to use Redux with react-redux.
Redux is a predictable state container for JavaScript apps.
It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.
It's very small library so it's easy to understand how everything works. It might be a good solution to your problem.
Todo app example
You can also check out awesome egghead.io free tutorial - Getting Started with Redux
Here is the answer about the redux benefits by its author Dan Abramov
The React documentation provides an answer.
For communication between two components that don't have a
parent-child relationship, you can set up your own global event
system. Subscribe to events in componentDidMount(), unsubscribe in
componentWillUnmount(), and call setState() when you receive an event.
Flux pattern is one of the possible ways to arrange this.

Categories

Resources