Does "immutable props" mean you can't call methods of objects on props?

Viewed 47

It seems that I can put an HTMLElement such as a Canvas on the props of a child and the child will happily draw on it. And I can see various useful cases where I want to do this sort of thing.

However, seems to break the rules "children should never modify their props".

It raises the question for me of what can a child do with an object it receives on props? Any method call you make on an object can cause that object's state to change (without you necessarily being aware), so does that mean you should not call methods on an object passed in on props?

1 Answers

The statement "children should never modify their props" isn't quite correct - it's more nuanced than that.

One of the general ideas behind React is for the appearance of the display - the view - to flow from React state as much as possible. That is, ideally, when starting up a script, if you were given the React state for all components being rendered, you'd be able to completely determine what the view should look like to the user.

Unfortunately, sometimes there's data that just doesn't flow naturally from state into the React view - such as with a tool (or library) that requires mutation, of which drawing on a canvas is one. In such a case, do your best to work within the React framework when you can, but if you have to mutate a non-React object in order to get the desired results... well, that's what you have to do, it's not a huge problem.

There would be problems if the React view depended on data present inside a mutated object (rather than the object providing its own view). For example, you can't do

const App = ({ obj }) => {
  useEffect(() => {
    setTimeout(() => {
      obj.foo = 'bar';
    }, 2000);
  }, []);
  return <span>{obj.foo}</span>
};
<App obj={{ foo: 'foo }} />

because React depends on data inside the object to decide what to render. If the object mutates, React won't know that it needs to re-render.

If, rather, an object gets mutated as part of the logic your app needs, but React's view doesn't depend on the mutated data, then you're just fine.

Another way of looking at it:

React state -> React view is just fine

Object that gets mutated -> Object view is just fine

Object that gets mutated -> React view is not fine

So

"children should never modify their props"

should be more like

"children should never modify their props if their props correspond to React state"

because the view that React provides flows from the state, and the view only knows when to re-render when the state is set anew (without being mutated).

does that mean you should not call methods on an object passed in on props?

As long as you're aware of what the methods do, and make sure that React principles don't get violated by calling the methods, feel free to call them. Calling a method that causes a non-React mutation (and whose mutation does not change data React uses to render) is sometimes a necessary evil.

Related