reactjs-How to pass a state element to child without reference? - javascript

In the above code,if x in control it is reflected in display.How to pass an element of a parent component's (i.e control) state so that change in parent's state will not affect the child (i.e display)?
class Display extends React.Component{
render()
{
return( <button>{this.props.x}</button> );
}
}
class Control extends React.Component{
state={
x:'Hello'
}
render()
{
const {x}=this.state;
return( <Display x={x}/> );
}
}

Here's an example. You can assign the prop value to an 'instance' variable in componentDidMount. ComponentDidMount will run only once, when Display first mounts. In the example below, it will assign the value of this.props.x to this.x. Using this.something creates an 'instance' variable that will be available anywhere in Display. It will not be updated/changed when this.props.x changes (assuming x is a primitive value like a string or number). And if you change the value of this.x it will not cause a rerender of Display.
class Display extends React.Component{
componentDidMount() {
this.x = this.props.x;
}
render()
{
return( <button>{this.x}</button> );
}
}
class Control extends React.Component{
state={
x:'Hello'
}
render()
{
const {x}=this.state;
return( <Display x={x}/> );
}
}

Related

Get the state of a class from anywhere like global variables

I have Parent class which has MainDiv and LoadngPopper.
In this case I want to get MainDiv state from LoadingPopper
class Parent extends React.Component{
render(){
return (
<MainDiv>
<LoadingPopper>
)
}
}
class MainDiv extends React.Component{
constructor(props) {
this.state = {
loading:0
}
}
}
class LoadingPopper extends React.Component{
render(){
//want to check MainDiv.state.loading here
return();
}
}
I can find how to give the parameter to parent to child or vice verse.
So, I can give the state from MainDiv -> Parent -> LoadingPopper
However in this case, I want to quickly access to MainDiv from anywhere like global variables.
Is it possible get the MainDiv instance directly from LoadingPopper?
Managing states inside a parent component allows accessing the states among its child components. (MainDiv and LoadingPopper)
Please check the official React documentation for more information:
https://reactjs.org/docs/lifting-state-up.html
Unless you have a huge and complicated component tree, I recommend simply sharing states from a parent component instead of using a state management library such as Redux to achieve this.
class Parent extends React.Component{
constructor(props) {
this.state = {
loading:0
}
this.toggleLoading = this.toggleLoading.bind(this);
}
toggleLoading() {
if(this.state === 0) {
this.setState({ loading: 1 });
return ;
}
this.setState({ loading: 0 });
}
render(){
return (
<MainDiv loading={this.state.loading} toggleLoading={this.toggleLoading} />
<LoadingPopper loading={this.state.loading} />
)
}
}
class MainDiv extends React.Component{
//set loading state here by using this.props.toggleLoading
}
}
class LoadingPopper extends React.Component{
//check loading state here
}

React : Storing child components in parent constructor as this.child - Is this a bad idea?

I am trying to store my child components in the parent constructor as attributes of the class instance. On the state change, I am expecting the parent (hence the child) to rerender and for the letter "b" to be on the screen verses "a". Why does this not work?
Does not show "b" on state change
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {letter : "a"};
setTimeout(() => this.setState({letter: "b"}, 1000);
}
this.child= <Child letter = this.state.letter>
}
render() {
return this.child;
}
}
class Child extends React.Component {
render() {
<p>{this.prop.letter}</p>
}
}
But when I do not store the child component as a class attribute of the parent, but instead render it directly in the render method, it works. The child component reflects the change. Is this because render creates a new JSX object every time it is run, and by storing the child jsx as a attribute of the parent object, I am essentially rendering that old child object?
Correctly Shows "b" on state change
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {letter : "a"};
setTimeout(() => this.setState({letter: "b"}, 1000);
}
}
render() {
return <Child letter = {this.state.letter}/>;
}
}
class Child extends React.Component {
render() {
<p>{this.prop.letter}</p>
}
}```
You can't return an object as render return statement, it should be most of the time a jsx so if you want to do your wrong way, you need something like this:
render() {
return <div>{this.child}</div>
}
But let's see why that's wrong, in React change in state or props will result in a rerender, and that's why you need to keep data in those places, otherwise like your case (if you change it like I showed above which is wrong), you get stale data and as you said the letter you're getting in the Child Component is old version and will not be updated
so let's say it in another way, the constructor function will only be called at the initialization and in that moment you set this.child attribute with the letter a, after 1000ms the state will change to letter b but you're constructor function will not be called again. so you still have the old value.
in the mean time because the state has changed from a to b render function will be invoked again, and here if you had the Child component in the render function as a jsx you get new data

React - passing 'this' as a prop

Is there any side effect I do not see by doing this ?
class App extends React.Component {
hello() {
console.log("hello")
}
render() {
return <Layout app={this}>
}
}
So later on I can refer to this.props.app.hello (and others) from Layout ?
This is not safe.
React will not know how to watch for changes, so you may miss re-renders. React uses === to check for state changes, and App will always be === to App, even when state or properties change.
Take this example:
class App extends React.Component {
constructor(props) {
super(props);
this.setState({text: 'default value'});
}
hello() {
this.setState({...this.state, text: 'new value'});
}
render() {
return (
<div onClick={this.hello}>
<Layout app={this}>
</div>
);
}
}
class Layout extends React.Component {
render() {
return <div>{this.app.state.text}</div>
}
}
When you click on the parent div, this.hello will be called, but the child component will not detect the state update, and may not re-render as expected. If it does re-render, it will be because the parent did. Relying on this will cause future bugs.
A safer pattern is to pass only what is needed into props:
class App extends React.Component {
//...
render() {
return (
<div onClick={this.hello}>
<Layout text={this.state.text}>
</div>
);
}
}
class Layout extends React.Component {
render() {
return <div>{this.props.text}</div>
}
}
This will update as expected.
Answer
There's nothing wrong in passing functions as props, as I can see in your example, the only thing you have to do is make sure your function is bound to the current component like the following example
Reference
React: Passing Functions to Components

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.

Categories

Resources