1

I'm working on a React Native project and I realized that React Native seems to break the React flow (Parent to children) props update.

Basically, I'm calling a "Menu" component from an "App" component, passing a prop to "Menu". However, when I update the "App" state, the props on "Menu" should update, but this doesn't happen. Am I doing something wrong?

That's my code:

App.js

import React from 'react';
import {
 View,
 Text
} from 'react-native';

import Menu from './Menu';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      opacity: 2
    }
  }

  componentDidMount() {
    setTimeout(() => {
      this.setState({
        opacity: 4
      });
    }, 3000);
  }

  render() {
    return(
      <View>
        <Menu propOpacity={this.state.opacity} />
      </View>
    );
  }
}

export default App;

Menu.js

import React from 'react';
import {
View,
Text
} from 'react-native';

class Menu extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      menuOpacity: props.propOpacity
    }
  }

  render() {
    return(
      <View>
        <Text>Menu opacity: {this.state.menuOpacity}</Text>
      </View>
    );
  }
}

Menu.propTypes = {
  propOpacity: React.PropTypes.number
}

Menu.defaultProps = {
  propOpacity: 1
}

export default Menu;
Pablo Darde
  • 5,844
  • 10
  • 37
  • 55

1 Answers1

4

React is not breaking data flow... You are. After initial state initialisation, you forget to update Menu's state later, when parent sends updated props.

Try this...

class Menu extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      menuOpacity: props.propOpacity
    }
  }

  componentWillUpdate(nextProps, nextState) {
      nextState.menuOpacity = nextProps.propOpacity;
  }

  render() {
    return(
      <View>
        <Text>Menu opacity: {this.state.menuOpacity}</Text>
      </View>
    );
  }
}
Andreyco
  • 22,476
  • 5
  • 61
  • 65
  • You can not update state like this inside willupdate – Codesingh Dec 25 '16 at 21:33
  • Please, why do you think so? It's legit way, does not break a thing and saves you another re-render. Take a closer look at constructor - state is initialised from prop passed by parent. I used very same pattern in `componentWillUpdate` method. Component *is about to update* (you cannot prevent this from happening) and state will be replaced with modified `nextState`. – Andreyco Dec 25 '16 at 21:58
  • Hey @Andreyco, your solution works. At first, thank you for the help. So, I have a question, why I need componentWillUpdate here and not in a pure React application? I did an example with pure React and all works fine without the componentWillUpdate. – Pablo Darde Dec 25 '16 at 22:50
  • 1
    You need it, because you initiated `state` from passed `props` (for reason unknown to me). You can completely skip `state` in your example and use stateless function component (that's what you call "pure react application"). However, if you need to compute state from prop in the future, this is one possibility :) – Andreyco Dec 25 '16 at 23:03
  • Ok, understood. I'm using state because my real Application uses "Animated.View" from React Native, which requires state. So, I was taking a look into the React's docs, and I found "componentWillReceiveProps", that works as well. Is there some reason I should use "componentWillUpdate" and not "componentWillReceiveProps"? – Pablo Darde Dec 25 '16 at 23:56
  • In this case, you can set animated property directly as class property. See this example. http://pastebin.com/aCPgxPkD I hope I got it right ;) – Andreyco Dec 26 '16 at 00:05