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.