All throughout my React learning saga I've heard it is bad to mutate objects, bad to write mutative functions...
and finally, bad to mutate the state:
- for displaying and posting data
- to write impure functions that change the source input
- to change a data source without making a copy.
With the principles of flow in mind, the initial logic of one way data flow whilst preventing mutation is to ensure the state shape remains the same and DOM-related events and operations are predictable and provide accurate results every time they're used.
My mindset has been shifted and challenged with Angular. It offers two-way binding and one-way binding on component properties. But due to two-way binding, I have to be aware of modifying a value in a component's model too. The way I get around this so far, has been to create class properties as empty objects or arrays with types declared, and to push or concatenate data to them. These properties become available as values that are iterated through and displayed on the view.
When I do encounter exceptions and dig deeper, I've discovered it depends. And this internal discussion of mine started with realizing I don't really knowing what it means to mutate an object or state on the component level, the module level, and the app level.
Below I'm discovering situations where mutation is ok if we understand its side effects.
Input fields and the like
Suppose I enter something into a form field. I've already mutated the state of that field. I can set its state, patch it, update it, read from it, display its value...etc. Form fields are meant to have its state mutated to facilitate capture of information for posting or internal calculations. Where mutation matters is that the its final state needs to be captured for posting or internal calculations.
Consuming APIs
If I'm simply consuming a huge API response object and displaying it, it probably makes sense to slice and dice it.
My instinctive mental shortcut is to just make the class methods pure and functional, but what if I have to extract and manipulate a value from a large JSON.parsed response object with all kinds of nested values into a new data structure?
If I deep-copy the huge response to extract and post the value, this large object stays in the lexical scope and may slow down operations. The original info always exists in the api endpoint anyway; it's not sacred.
On the other hand I could try to turn all its values into arrays so I could concatenate select parts to a class property that could be made available for display.
If no other components use this api response's body it would be ok to push and delete values out of it. (An additional concern I'd have is the order of operations here... making sure the data arrives in the component state before manipulating and displaying it)
Temporary dictionary objects and arrays
Learned this one from Java programmers at my work: creating a temporary object to store a dictionary of key values and pushing it into a class property that's an array, so that we use it to iterating through the front end.
I don't know of a better solution but please share if you do!
Functions/Class methods that coerce type
These may be redundant if you're already using Typescript, but I find that in the case where optional input entries might possibly be null or empty, checking and coercing type to an empty string might be helpful in making the program run. That's just my opinion, and maybe not best practice. I would love to hear what I could do!
Whether other components are dependent on the mutated state or object
This is something I have to think hard on when I'm building early on... what other components might use this logic?
In terms of writing helper functions, class methods/inline actions, those in the React camp are probably like me, inducted into a functional programming school-of-thought where any function that does not produce the same result, and mutates the original data source is bad, bad, bad. However, some things to consider if we must mutate are:
- Do we need that original value for anything else?
- Does this process need to be reversed and why?
- Have we included conditionals that would produce a range of results, so are they effective in producing a reliable range of results?
- And if we keep that original source around, should we garbage clean at the end?
As Kieran from TorontoJS put it, I need to be mindful of what mutation does instead of treating any programming paradigm I've read online as the absolute canonical practice.
What do you all think?
Top comments (0)