long story short I need to connect react-hook-form into redux in real time - have the formState in a dedicated slice.
I have scoured the internet for solutions and everyone says "onSubmit, also dispatch". My issue is that I need to know things like isDirty, isValid, values of certain forms in components outside the forms scope, that are dependent on the form state & values.
I was considering the fields onChange methods can easily dispatch the information I need... Is it bad practice to do this? is there a more... elegant way to get this done?
Apologies for the lack of "code driven question" - I am looking to hear those who've tried this what approaches they took as this can have performance consequences.
Related
According to Redux Toolkit's documentation, and many answers here on Stack Overflow, storing non-serializable values in Redux is not recommended, and that's why they print warnings in the console when that happens.
However, the only issues they raised were that it could bug Redux's dev tools and that it wouldn't be possible to serialize data when needed.
If I don't need these features, is there any other reason, specially when it comes to performance, to not disable these warnings?
Being able to store classes in Redux would make it easier to type check objects, including nested ones, without using "value is X" workarounds in TypeScript.
As the docs (that I wrote! :) ) tell you: the code will run, technically.
But it absolutely does lead to potential mutation issues, as well as wasting the ability to see that data in the DevTools, and the DevTools are one of the primary reasons to use Redux in the first place.
So, as all the answers say: we strongly encourage that you do not put classes in the Redux state. That's not how Redux is meant to be used.
If you absolutely want to, I guess you can. But it's not the right approach, and it really is likely to cause issues down the road.
(I am curious what you mean by "easier to type check objects"...)
I know that we are not suppose to mutate the state because, the app re-renders based on the fact if there has been changes in the reference in previous state and next State, but what id I do something like this
reducerFunction = (state, action) => {
state.value = action.value;
return {...state}
}
Here I am passing a new reference, so is there anything wrong with it which could happen because of state mutation
This will work but you are mutating older state and then creating new one and return it. This is not recommended. In some case this may be an issue if you need undo functionality.
Two problems that I can think of.
You would loose (or mess up) the undo history feature of redux. This comes in really handy sometimes, especially when you are dealing with lots of data.
You are assuming synchronous execution of the code. Redux (and JS in general) makes no such guarantees. In an application where you are updating the store with anything computer-generated (practically anything that is not user inputs) and reading it back somewhat quickly, this would mess up the state and you will have a Race Condition.
Generally, it is a good idea to follow the implementation guidelines to have your code run predictably. Sometimes there is error checking for things that are non-standard, simply because it might break the code. It can potentially be a security issue. I do it all the time when I write APIs.
I could not understand what the below lines on first page of REDUX mean https://redux.js.org/introduction/motivation
This complexity is difficult to handle as we're mixing two concepts
that are very hard for the human mind to reason about: mutation and
asynchronicity. I call them Mentos and Coke. Both can be great in
separation, but together they create a mess. Libraries like React
attempt to solve this problem in the view layer by removing both
asynchrony and direct DOM manipulation. However, managing the state of
your data is left up to you. This is where Redux enters.
Note: Marked bold are the strong lines I was enable to understand.
Mutation simply means you will need to be able to change the state of things (variables, global store etc) and also you will need to be able to react to when those things change.
Asynchronicity means that events may occur at different times - you can't predict precisely when they will occur or when they will complete.
Therefore, in an app that has to be able to change data (mutation) and can have that data change asynchronously, things get difficult.
I'd suggest you read up more on redux (and in general, libraries that promote a specific "flow" of data mutations). At the heart of the issue is that if data can mutate at any time whereby you are changing the data directly and it can be changed asychronously (for instance via API calls to external services) then without careful thought/use of libraries and understanding, your app can turn into an unholy mess.
I'm learning redux and am struggling to understand why state has to be immutable. Could you provide me with an example, in code preferably, where breaking the immutable contract results in an not so obvious side effect.
Redux was originally invented to demonstrate the idea of "time-travel debugging" - being able to step back and forth through the history of dispatched actions, and see what the UI looks like at each step. Another aspect is being able to live-edit the code, reload it, and see what the output looks like given the new reducer logic.
In order to be able to properly step back and forth between states, we need to make sure that reducer functions have no side effects. That means data updates need to be applied immutably. If a reducer function actually directly modifies its data, then stepping back and forth between states will cause the application to behave in an unexpected fashion, and the debugging effort will be wasted.
Also, the React-Redux library relies on shallow equality checks to see if the incoming data for a component has changed. If the data references are the same, then the wrapper components generated by connect assume that the data has not changed, and that the component does not need to re-render. Immutable data updates means that new object references are created, and thus connect will see that the data has changed and the UI needs to update.
Two Ideas
There are two ideas about immutability that you need to understand:
Mutate the state only in the reducers
Using an immutable data structure
Mutate the state only in the reducers
Redux tries to ensure that you only mutate the state in the Reducers. This is important because it makes easier to think about your application data flow.
Let's say that a value is not displayed in the UI as you expected or that a value that should have changed still showing its original value.
In that case, you could just think about which reducer is causing the mutation and see what went wrong.
This makes thinking about Redux issues very simple and makes developers highly productive.
Sometimes you can mutate the state in a view or in an action by mistake. If you think about the life-cycle:
Action -> Reducer -> Views-> Action
If the state changes in a view and then an action is triggered the state change could be override. This would make very hard to find out what is going on for developers. We solve this by mutating state only in the reducers.
Note: another nice thing is that reducers are pure functions and all the async stuff takes places in the actions/middleware. So all side effects take place in the actions/middleware layer. Actions are our connection with the external world (HTTP, Local Storage, etc.).
Using an immutable data structure
As I have already mentioned, sometimes you can mutate the state in a view or in an action by mistake. To reduce chances of this happening we can make state mutations explicit by using and immutable data structure.
Using immutable data structures also has performance benefits because we don't need to perform deep equality checks to check for mutations.
The most commonly used provider of immutable data structures is immutable.js.
I think the key ideas would be
Easy to replay any given situation/test flow - you can replay with the same actions starting from the same initial state
Fast component re-rendering - because the reference is changed and not its values, it is much much faster to test the change
Of course, there are other aspects and I suggest this nice article which explains in more details.
Maybe someone can explain this to me, but these two principles, in my opinion, contradict each other and it's really hampering my progress in learning Redux.
State is read-only and Changes are made with pure functions
The first line after State is read-only is this: "The only way to mutate the state...". If something is read-only then it shouldn't be able to be mutated in the first place. Even in the Egghead videos the states are always labeled as const, but are still changed defeating the purpose of const.
Can someone please explain to me how these are not diametrically opposed ideas?
There's no contradiction, though certainly the confusion is understandable.
A good way to think about it is to draw an analogy between React state and Redux state.
In React, you only ever define your component state once, in the constructor() or getInitialState() method. From that point on, you always treat this.state as read-only, you never assign anything to this.state. To change the state, you call this.setState().
The same is true in Redux. You define the state - or each different part of the state - once. Typically it's called initialState and assigned as the default value of the state parameter of your reducer. Treating state as read-only means never overwriting or mutating the state. The only way to change the state is with the return value of your reducer.
Or, in short...
I think your real hang up is over the state being both changeable and read-only, so let me be more pithy:
A CD-ROM is read only, but I can eject the CD and replace it with another.
The state is read-only, as far as the world outside Redux is concerned. Think of it as a view on the append-only sequence of application events (actions) that have happened. You can generate new actions, and those will result in the state becoming different.
Of course, it's the real world and there is mutability somewhere. As Rich Hickey famously put it:
“If a tree falls in the woods, does it make a sound? If a pure
function mutates data to produce an immutable value, is that ok?” ~
#richhickey
But as much as is practically possible, you write your application without directly mutating things. Instead, you describe the changes you would like to see (dispatching actions), and a framework (Redux) carries them out, using your reducers to create the entire view of the store (the state) at once, and through React's props, a new view is generated as a result.
This is inspired by the concept of functional reactive programming. In this paradigm, all functions are pure, and you handle the concept of change over time by representing "what you would do with a value, if it were to have changed". In some sense, you conceptualize the entire past and future of a variable as an immutable function, whose future you simply happen not to know yet. Sorry if that got too philosophical.