Hey i'm new to RTK toolkit and just trying to access state from isolated component to store state from mutation, so i can skip passing them to that component.
I can see the result from mutation in redux store behind the cashe key, but how to access the store data from isolated component?
I read the documentation at least twice and saw that if it's QUERY i can pass useGet** hook with the same args and could get the result. But my case is to access result from mutation (POST query).
Just in case i can create selector to the whole state:
export const selectSubmitStatus = (state) => state[createApi.reducerPath];
and possibly manual filter current item, but it could be easier to access mutation submitState with selector and passing cashe key or?
Simmilar problem here described
Related
I'm learning redux (in Flutter using Firestore, but I don't think that matters), trying to get beyond the basics, and I'm confused about where 'computed state' (not even sure what to call it) should go.
Say I have app state like this:
user: an instance of user
movies: a list of user's movies
recentFavoriteMovie: one of the movies above that user has marked "favorite" and has the most recent creation date
I'm able to set user (login success action) and request user's movies (login success middleware). When the movies query completes, I'm confused about where to initialize recentFavoriteMovie. There seems to be many choices....
SetMovies middleware can compute it, and then call a SetRecentFavorite action.
Can the SetMovies reducer do it? Or is that considered a side-effect of the reducer, which is not allowed?
I'd like to do it lazily. Is it considered okay in redux to give the app state object a method that computes and caches it? If so, I'd still need to clear the cached value when a new movie list is set. But that seems like the same problem as (b) above.
I could put the movies property and favoriteMovies (property or method) in my user object (they kinda belong there), and then just dispatch an UpdateUser action each time one or the other changes. In general, I don't know when/whether to "promote" some sub attribute of my app state to the top level so the app can react to it.
Are all or any of these valid choices? I hope this makes sense as a question. I might even be too behind the curve to ask this properly.
You almost ther with computed state. From documentation
Reselect provides a function createSelector for creating memoized selectors. createSelector takes an array of input-selectors and a transform function as its arguments. If the Redux state tree is changed in a way that causes the value of an input-selector to change, the selector will call its transform function with the values of the input-selectors as arguments and return the result. If the values of the input-selectors are the same as the previous call to the selector, it will return the previously computed value instead of calling the transform function.
That is essentially what yu want with lazy selection of movies.
In state you store user and movies. Some movies marked as favorites for specific user (so when user marks movie as favorite you only modify movies and not re-run selector).
When some component needs list of favorite movies, it calls selector which computes derived state (list of favorite movies) and returns it. Also selector will memorize results and recompute them only when store changes but not on each render.
This approach can be considered best practice as you may later implement some filters for movies list and selectors will help to extract filtered list of movies.
When using selector you don't required to store selected data (list of favorite movies) in you store.
Computed state is used in mapStateToPros for each component that require computed state like so
const makeMapStateToProps = () => {
const getFavoriteMovies = makeGetFavoriteMovies();
const mapStateToProps = (state) => (
{
favoriteMovies: getFavoriteMovies(state.user, state.movies),
movies: state.movies,
user: state.user
});
return mapStateToProps;
}
And makeGetFavoriteMovies may look like
const getFavoriteMovies = (state) => state.movies;
const getUser = (state) => state.user;
export function makeGetFavoriteMovies () {
return createSelector(
[getFavoriteMovies, getUser],
(favoriteMovies, user) => {
// Here can be complicated logic to select only favorite movies
return movies.filter (movie => movie.isFavorite);
}
);
)
Reducer and/or middleware can compute favorite movies list. But this is not their responsibility. So to better separate concerns its better to use selectors for this task.
Also there is not reason for specific middleware (ogin success middleware). You may implement logic in actions and reducer.
I run a chat application with Firebase Firestore and it works all super well, however I'm running into the following issue:
For paginating my conversations & chats I use query cursors for my listeners. I save these query cursors into my state (vuex) so I can access them later when needed. That works and I can paginate my chat messages and conversations.
I create query cursors like so:
const query = await ref.get()
const cursor = query.docs[query.docs.length - 1]
commit('SET_CONVERSATIONS_QUERY_CURSOR', cursor)
And later use them in the next query like so:
.startAfter(state.conversations.queryCursor)
Everything actually works perfect.
My issue now is that that cursor saved in my state seem to be updated regularly (...why Firebase?) & especially directly. This gives me the following error messages when using vuex strict-mode (-> not allowed to access the state directly):
app.js:506 Error: [vuex] Do not mutate vuex store state outside
mutation handlers.
Now I of course want to use strict mode to avoid mutation state directly, but I can't due to the query cursors in my state.
I tried to clone the cursor before saving in to the store, but shallow clones did no good and deep clones did not work because of Converting circular structure to JSON.
So...
Is there a recommended way on how to store query cursors for later use?
Are there options to just store the id of a document and later "recreate" a query cursor?
Thanks!
You can prevent javascript object from getting modified by using Object.freeze(obj).
So in your case it should be const cursor = Object.freeze(query.docs[query.docs.length - 1])
When using a selector, I thought that I could do whatever I wanted with the variable without modifying the state, so I was surprised that the state became mutated.
So if this is wrong (in a redux saga):
const filters = yield select(state => state.filters.filters);
filters.terms['helloo'] = "mutated";
//send data with request
yield put(requestData(filters)
How come that first line is a direct reference to the state?
Anyway, if I try using Object.assign, it also mutates state:
const filters = Object.assign({}, yield select(state => state.filters.filters));
filters.terms['helloo'] = "mutated";
How do I create a selection that is a copy of the state?
There's truly no "magic" involved here. Redux's getState() is literally just return state, and both hand-written selectors and Reselect return whatever you have written the functions to return. So, in that example, filters is the actual object reference that's nested inside the store state, because that's what your function returned.
Per the Redux docs page on "Immutable Update Patterns", you need to copy all levels of nesting that you want to update. In your example, you're making a copy of filters, but not filters.terms, so terms is also still the original object that's in the store. You would need to make a copy of that as well, and modify the copy.
I have stored a payload in the redux store. I couldn't access the store object. How to access the store object? I wanted to access it by redux-saga. I tried even by normal redux to access store but could'nt!
I wanted to access it by redux-saga. I tried even by normal redux to access store but could'nt!
In general case redux-saga combines two things - redux middleware and independent process manager. If you need only to fetch and directly manipulate with redux internal state without process managing, probably, it's better to write own simple middleware (https://redux.js.org/docs/advanced/Middleware.html ) and maybe compose it with saga.
Of course, you can easily use select effect (https://redux-saga.js.org/docs/api/#selectselector-args ). but take in account, that middleware first forwards the action to the reducers and then notifies the Sagas. This means that when you query the Store's State, you get the State after the action has been applied.
Most likely it's better to store mandatory information info current saga's closure, for example, before while-true loop in dedicated saga process.
function* someSaga() {
const localState = {};
while(true) {
const action = yield take('ACTION_PATTERN');
// some logic to dispatch the action
yield put('SOME_AFTER_ACTION')
}
}
The store has a method called getState that will return the current state of the store.
What prevents code somewhere in my application from (accidentally) modifying the returned state from store?
Let's say i call this:
let state = store.getState();
state.someProperty = 'fun';
The implementation that i've found on getState on the store object simply returns the inner state object that gets overwritten with each new action.
const getState = () => state;
In between actions/new states what prevents code from modifying the state that will be read by another subscriber? In my above example, setting someProperty to 'fun' will persist inside the store on the state property, until overwritten.
While i'm obviously not supposed to modify the state, a simple mistake might bind the state to some component that (unknowingly) modifies its inputs - perhaps on a 2-way binding in an angular environment?
<app-some-component [user]="state"></app-some-component>
Shouldn't getState() be implemented as a clone of its state model?
P.S. This is not specifically related to Angular - which is why i didn't add the tag - to allow more people not used to Angular to answer the question.
The answer is: nothing :)
The core Redux library itself technically doesn't actually care if state gets mutated or not. You could actually mutate in your reducers, or have other parts of your app get the state tree and mutate it, and the store itself wouldn't know or care.
However, mutation will break time-travel debugging, as well as make tests unreliable. Even more importantly, the React-Redux library assumes that you will handle your state immutably, and relies on shallow equality comparisons to see if the state has changed. (This is the reason why "Why isn't my component re-rendering?" is in the Redux FAQ. 99.9% of the time, it's due to accidental mutation.)
If you are concerned about mutation, you can use a library like Immutable.js instead of plain JS objects, or use one of the several tools for freezing your state in development to catch mutations.