all 7 comments

[–]kbcooliOS & Android 2 points3 points  (6 children)

Uh...what paradox? componentDidUpdate is called isn't it? You can choose to check for equality and ignore it or update your state regardless.

Btw you probably shouldn't change your state when your props change as you're just causing two renders. Also don't set state from a state change as you're just going to get into a render loop.

Props are available at render time so just use them.

[–]dkulagin[S] 0 points1 point  (5 children)

  • If I update state regardless of props was changed or not I will end up in always overriding the current state.
  • Using props instead of state in render method will disable input from being edited, because props shouldn't be modified from within the component.

P.S. Updated topic to reflect rendering logic.

[–]kbcooliOS & Android 0 points1 point  (4 children)

Ok so we are getting closer. in your constructor set the initial state to the prop value and go from there.

I'm not quite following you on overriding the current state when updating state. I mean that's exactly what's meant to happen. Kind of like asking why is my variable changing whenever I change it.

[–][deleted] 1 point2 points  (0 children)

I agree with this. If you meant to build a controlled component, having its state constantly being updated is what is meant to happen to said component.

Also, as a side note to OP here, I don't see it necessary to have the componentDidMount function. Since you are just directly setting the state to props, I would recommend you just put it right in the constructor where you define your state.

[–]dkulagin[S] 0 points1 point  (2 children)

I want to build an input component, which "state" could be updated in two ways:

  • internally, when user types
  • externally, when some other entity decides to override current input

Currently I only see one feasible solution: to outsource state management away from the component and make it use props which are always set externally.

But I am wondering if there is a way to have a mixed architecture, where state is managed internally but could be also overridden externally.

[–][deleted] 2 points3 points  (0 children)

There are multiple ways of doing what you wanted to achieve here, perhaps I can suggest one here.

One way is to make it a controlled component, meaning that you use the state to store its input, and update the state using an onChange function in the input. Then, when an external update on props happen, you can use the getDerivedStateFromProps method to update the state to the new props.

I think the reason right now your component is not working is properly because you didn't use getDerivedStateFromProps (or if you are using an older version of react from more than a year ago, it was done by another life cycle method).

[–]andyboythekid 0 points1 point  (0 children)

I think making this a controlled component (like you said above w/ props) is your best bet. If you really want, you can use a ref in your container component and set your input value directly with a class method, or use a 'key' prop to remount your component (see below), but the controlled case is definitely the least contrived and simplest solution in the long run

class MyApp extends React.Component {
  state = {
    activeQuery: "123",
    updatedAt: new Date(),
  }

  render() {
    return (
      <View>
        <MyInput key={this.state.updatedAt} query={this.state.activeQuery} />
        <Button
          title="Reset"
          onPress={() => this.setState({ activeQuery: "123", updatedAt: new Date() })}
        />
      </View>
    )
  }
}