Vuex error: "Do not mutate vuex store state outside mutation handlers." - laravel

I have a button on my website that performs the following action:
this.$store.commit('SET_THREAD_UPDATE', thread)
'thread' is an object consisting of multiple properties and objects and when the function is called there might be only a small change within an object of 'thread' or one of its properties.
'SET_THREAD_UPDATE' is a Vuex mutation and the only one of many that causes problems even though I am not doing anything differently.
const state = {
threadUpdate: {}
}
const mutations = {
SET_THREAD_UPDATE (state, userObj) {
state.threadUpdate = userObj
}
}
When the button that triggers the commit is pressed the first time, everything works like expected. But then, from the second time forward I get two errors and the commit doesn't do anything:
[Vue warn]: Error in callback for watcher "function () { return this._data.$$state }": "Error: [vuex] Do not mutate vuex store state outside mutation handlers." (found in <Root>)
Error: "[vuex] Do not mutate vuex store state outside mutation handlers."
I can't figure out the error. It doesn't make sense because I am using a mutation to change the state. Ideas anyone? Thanks!

Solution to the problem was to use JSON instead of regular JS objects. Not sure why though.

Related

Followed different suggestions but still get "Invalid hook call. Hooks can only be called inside of the body of a function component"

I'm getting
Error: Invalid hook call. Hooks can only be called inside of the body
of a function component.
I followed different suggestions here on other questions and also on other forums. The last I tried is this one, but still I can't figure out what's the problem with my code:
function myFunc() {
const locale = useSelector((state) => state.locale);
return <></>;
}
I am really new to react so don't hesistate to tell me if you need me to post further details

How can I stop an Apollo GraphQL query with required exported variables from fetching when those variables are removed

The Problem
When navigating away from query components that use the state of the app route as required variables, I get GraphQL errors of the sort:
Variable "$analysisId" of required type "ID!" was not provided.
"Navigating away" means, for example, going
from: /analysis/analysis-1/analyse/
to: /user-profile/
Background
I am building an SPA using Apollo GraphQL, and I have some queries which follow this pattern:
query Analyse($analysisId: ID!) {
location #client {
params {
analysisId #export(as: "analysisId")
}
}
analysis(analysisId: $analysisId) {
id
# ... etc
}
}
The location field gets a representation of the SPA router's state. That state is held in an Apollo client "reactive variable". Query components are programmed to not begin subscribing to the query unless that reactive variable exists and has the required content.
shouldSubscribe(): boolean {
return !!(locationVar()?.params?.analysisId);
}
Params represents express-style URL params, so the route path is /analysis/:analysisId/analyse.
If the user navigates to /analysis/analysis-1/analyse, the query component's variables become: { analysisId: "analysis-1" }`. This works fine when loading the component.
What I Think is Happening
When the component connects to the DOM, it checks to see if it's required variables are present in the router state, and if they are, it creates an ObservableQuery and subscribes.
Later, when the user navigates away, the ObservableQuery is still subscribed to updates when suddenly the required analysisId variable, exported by the client field location.params.analysisId is nullified.
I think that since the ObservableQuery is still subscribed, it sends off the query with null analysisId variable, even though it's required.
What I've Tried
By breaking on every method in my query component base class, I'm reasonably sure that the component base class is not at fault - there's no evidence that it is refetching the component when the route changes. Instead, I think this is happening inside the apollo client.
I could perhaps change the schema for the query from analysis(analysisId: ID!): Analysis to analysis(analysisId: ID): Analysis, but that seems roundabout, as I might not have control over the server.
How do I prevent apollo client from trying to fetch a query when it has required variables and they are not present?
This seems to be working fine so far, in my HttpLink, src/apollo/link/http.ts:
import { ApolloLink, from } from '#apollo/client/link/core';
import { HttpLink } from '#apollo/client/link/http';
import { hasAllVariables } from '#apollo-elements/lib/has-all-variables';
const uri =
'GRAPHQL_HOST/graphql';
export const httpLink = from([
new ApolloLink((operation, forward) => {
if (!hasAllVariables(operation))
return;
else
return forward(operation);
}),
new HttpLink({ uri }),
]);

class property doesn't update with redux

Context
I've built an app that renders mails from your outlook accounts into a web page in react.
I'm trying to set a "viewed" boolean as a class property fed by redux store and change it from within the component (that change must impact in redux to manage that change on the overall app )
Problem
As you might see on below's code, i initiate the instance variable in the constructor with the given information from redux reducer,
I've tested with a bunch of console logs if the action creator successfully updates that information on the store and it actually does.
My problem is that my instance variable (this.viewed) isn't updating with redux's reducer information (that actually does update)
import React from "react"
import {connect} from "react-redux"
import { bindActionCreators} from "redux"
import * as QueueActions from "../redux/actions/actionCreators/queueActions"
class Mail extends React.Component {
constructor (props){
super(props)
this.id = props.id
this.viewed = props.mails.find(mail => mail.id = this.id).viewed
}
}
componentDidMount = () => {
this.props.queueActions.setMailToViewed(this.id);
}
function mapStateToprops () {
return {
mails : store.queueReducer.mails,
}
}
function mapDispatchToProps() {
return {
queueActions : bindActionCreators( QueueActions, dispatch ),
}
}
export default connect ( mapStateToprops, mapDispatchToProps ) (Mail)
Question
what am i doing wrong here?
why does the viewed property on redux updates but my instance variable that feeds from that very same information doesn't?
shouldn't this.viewed update whenever the props that provided the information update?
Can't i update this information from props without using a state?
I think the issue is because the assignment to this.viewed happens in the constructor, which is only called once. When the redux store updates, the component will get new props but the constructor will not be called again, so the value will not be updated. Hopefully these links will help explain the issue:
ReactJS: Why is passing the component initial state a prop an anti-pattern?
https://medium.com/#justintulk/react-anti-patterns-props-in-initial-state-28687846cc2e
I'd also recommend reading up on functional components v class components and why functional components are used alot now instead of class ones. A starting point:
https://medium.com/#Zwenza/functional-vs-class-components-in-react-231e3fbd7108
If you used a functional component, you could use the useSelector hook to access the store and update your components.
Hope this this useful, I'm quite new to react so apologies if you're looking for something more, but I hope this helps.

NGXS State documentation

I'm new to NGXS and I'm trying to fully understand the docs so I can start using it knowing what I'm doing.
There is one thing I don't understand in this code snippet from here.
export class ZooState {
constructor(private animalService: AnimalService) {}
#Action(FeedAnimals)
feedAnimals(ctx: StateContext<ZooStateModel>, action: FeedAnimals) {
return this.animalService.feed(action.animalsToFeed).pipe(tap((animalsToFeedResult) => {
const state = ctx.getState();
ctx.setState({
...state,
feedAnimals: [
...state.feedAnimals,
animalsToFeedResult,
]
});
}));
}
}
Just below this code, it says:
You might notice I returned the Observable and just did a tap. If we
return the Observable, the framework will automatically subscribe to
it for us, so we don't have to deal with that ourselves. Additionally,
if we want the stores dispatch function to be able to complete only
once the operation is completed, we need to return that so it knows
that.
The framework will subscribe to this.animalService.feed, but why?
The action, FeedAnimals, uses the injected service, AnimalService to feed the animals passed in the action's payload. Presumably the service is operates asynchronously and returns an Observable. The value of that Observable is accessed via the tap function and is used to update the ZooState state context based on completing successfully.
In order to use NGXS specifically and Angular in general, you really have to understand RxJS... here's my goto doc page for it

Finding object in array initial state React-Redux app

I am currently working on an app that do not support server rendering, so i have to have an empty state when the client loads the app. Then a fetch is dispatched and the state is soon updated.
I have a component (some kind of editor) which should find an object based on a url-parameter. My mapStateToProps function looks something like this:
const mapStateToProps = (state, ownProps) => {
return {
book: state.library.list.find(function(book){ return book.id === ownProps.params.book_id})
}
}
this.props.book is undefined when the component runs getInitialState, so it does not get the update when the state is fetched. I get the following error in the console of my browser when the component loads:
TypeError: undefined is not an object (evaluating 'this.props.book.title')
From there on the editor remains empty, even when the state is received from the server later on.
Any idea of how i can solve this problem?
What you need to do is put a watch when you are loading data from this.props.book to not be an undefined
if(this.props.book) {
//do something with this.props.book
}
Solution: Preload the store on the server
I finally found an answer to my problem. What i did, was to check upon every request if the user was logged in (through JSON web tokens). If the user was logged in, i preloaded the state and sent it with the first request (assigned it to window._PRELOADED_STATE_ with a script tag in the response string).
Then i also added two lines on the client code
const preloadedState = window.__PRELOADED_STATE__
const store = createStore( rootReducer, preloadedState, applyMiddleware(apiMiddleware, thunkMiddleware) );
then the store was updated before the editor component asked for it.
This solution is based on some ideas introduced at redux's home page http://redux.js.org/docs/recipes/ServerRendering.html

Resources