How do I update a store that is in local storage with SvelteKit? - sveltekit

I am trying to update a store that is in local storage when I fetch data from Supabase.
The store always appears blank in the browser inspector even after using set() or update() or just by doing store.value = anotherValue. I have looked over the docs for this and looked through different tutorials but nothing has this specific use case.
If I do let firmNameVar = firmStore.firmName then I can get the value but I still don't see it in the browser inspector in local storage.
The Store Code:
import { writable } from "svelte/store";
import { browser } from "$app/environment";
export const storedFirm = JSON.parse(browser && localStorage.getItem("firmStore")) || {
firmID: '',
firmName: '',
firmAddress: '',
firmPhoneNumber: '',
firmWebsite: '',
firmType: '',
firmMembers: [''],
firmProjects: [''],
firmRoles: [''],
firmPermissionsID: '',
firmComplete: Boolean,
completeYourProfile: Boolean,
buildYourTeam: Boolean,
definePermissions: Boolean,
aboutYourWork: Boolean,
errorConnectingToSupabase: Boolean
};
export const firmStore = writable(browser && storedFirm);
firmStore.subscribe(
(val) => browser && (localStorage.firmStore = JSON.stringify(val))
);
Code to Update the Store:
import { firmStore } from "/src/stores/firmStore";
///CONNECTING TO DATABASE
async function queryFirmDatabase(){
const { data: firm, error } = await supabaseClient
.from('firms')
.select('id, firm_name,firm_address, firm_phone, firm_website, firm_projects, firm_complete, complete_your_profile, build_your_team, define_permissions, about_work')
.eq('id', clientUser.orgID)
if (firm){
///CONNECTED TO DATABASE AND TRYING TO ASSIGN VALUE TO STORE OBJECT
const [fetchedUser] = firm;
try {
firmStore.firmName.set(fetchedUser.firm_name);
} catch (error) {
console.log("Doesn't work")
}
} else {
console.log("THERE WAS AN ERROR FETCHING FROM FIRM DATABASE")
console.log(error)
}
}

This is simply not valid:
localStorage.firmStore = JSON.stringify(val)
You need to use localStorage.setItem(key, value).

Related

How to set a value in input automatically

I'm using a hook that fills in my inputs automatically, according to the zip code the user enters. Then the user's address, street, etc are filled in automatically.
However, for the input to be filled in automatically, the component is re-rendering.
As my form is a modal it opens and closes again because of rendering. I need to make the user fill in the zip code, the inputs are filled in real time.
Can you help me with this?
useCEP Hook:
import { useState } from 'react'
import { api } from 'services/apiClient'
interface Cep {
bairro: string
logradouro: string
localidade: string
uf: string
}
export function useCep() {
const [checkCep, setCheckCep] = useState<Cep>()
const getCEP = async (e) => {
const cep = e.target.value.replace(/\D/g, '')
try {
const { data } = await api.get(`https://viacep.com.br/ws/${cep}/json/`)
setCheckCep(data)
} catch (err) {
console.log(err)
}
}
return { checkCep, getCEP }
}
Component:
const { control, formState, register, reset } = useFormContext()
const { checkCep, getCEP } = useCep()
useEffect(() => {
reset({
responsible: [
{
address: checkCep?.logradouro,
district: checkCep?.bairro,
city: checkCep?.localidade,
state: checkCep?.uf,
name: '',
email: '',
student_name: [],
cep: '',
residence: '',
telephone: '',
sex: ''
}
]
})
}, [checkCep])
<Input
name="cep"
type="number"
label="Cep"
{...register(`responsible.${index}.cep`)}
error={errors?.responsible?.[index]?.cep}
onBlur={(e) => getCEP(e)}
/>
{...}
Maybe you can try to use the setValue method instead of reset as it will reset the form.
https://react-hook-form.com/api/useform/setvalue

Apollo Client cache does not update

I am using Apollo Server / Client and the cache does not seem to work on update mutations. (Create, Delete). The server gets updated but nothing happens on the front end. I have to reload the page to show the new item / show change of an item.
I followed the Apollo docs and modeled it after their sandbox implementation.
Let me know if you need more of my code, thank you.
Here is my code:
<form
onSubmit={(e) => {
e.preventDefault();
createUser(
{
variables: {
name: input.value,
email: input.value,
password: input.value
}
},
{
update(cache, { data: { createUser } }) {
cache.modify({
fields: {
allUsers(existingUsers = []) {
const newUser = cache.writeFragment({
data: { createUser },
fragment: gql`
fragment NewUser on User {
name
email
}
`
});
return existingUsers.concat(newUser);
}
}
});
}
}
);
}}
>
You need to provide an id property in the writeFragment method. Here's the example on the docs:
client.writeFragment({
id: '5',
fragment: gql`
fragment MyTodo on Todo {
completed
}
`,
data: {
completed: true,
},
});
Also, writeFragment returns void, so you need to use readFragment to get the data you want, or just use the data available in the mutation's result

How to use react context with nested mobx stores?

I have two stores: formStore and profileStore
FormStore
export class ProfileFormStore {
#observable editing = false;
profileStore = new ProfileStore(this.roleId);
originalValue?: ApiModel | null;
#action.bound
startEdit() {
// this.originalValue = this.profileStore.toJson();
/* if uncomment above, next error thrown
RangeError: Maximum call stack size exceeded
at initializeInstance (mobx.module.js:391)
at ProfileStore.get (mobx.module.js:381)
at ProfileStore.get
*/
this.editing = true;
}
}
ProfileStore
export class ProfileStore {
#observable userProfile: ApiModel = {
userProfile: {
newsAndUpdates: false,
email: "",
phone: "",
lastName: "",
firstName: "",
},
};
#observable email = "";
#action.bound
fetch() {
// this.fromJson(this.actions.fetch());
console.log("start");
this.email = "qwe";
console.log("end");
}
#computed
toJson(): ApiModel {
return {
userProfile: {
firstName: this.userProfile.userProfile.firstName,
lastName: this.userProfile.userProfile.lastName,
phone: this.userProfile.userProfile.phone,
email: this.userProfile.userProfile.email,
newsAndUpdates: this.userProfile.userProfile.newsAndUpdates,
},
};
}
}
And I want to use contexts
const formStore = new ProfileFormStore();
export const profileFormContext = React.createContext({
formStore,
profileStore: formStore.profileStore,
});
export const useProfileContext = () => React.useContext(profileFormContext);
And there are two components: form and formControl
const controls = {
admin: (<><ProfileName /><Email /></>),
user: (<><ProfileName /></>)
};
export const Form = () => {
const { formStore, profileStore } = useProfileContext();
// this.fromJson(this.actions.fetch()); // if uncomment throws 'Missing option for computed get'
return <form>(controls.admin)</form>
}
export const ProfileName = () => {
const { formStore, profileStore } = useProfileContext();
formStore.startEdit(); // check form store, when assigning from profileStore get overflow error
return formStore.editing ? <input value='test' /> : <label>Test</label>
}
So there are two kinds of errors:
When accessing observables from ProfileStore that is part of FormStore
When updating observables in ProfileStore that is part of FormStore
the FormStore working well
both stores injecting via React.useContext have followed these example https://mobx-react.js.org/recipes-context , however their stores are not nested. I made them nested, beacuse I wanted to get access to profileStore from formStore
What do these errors mean? How to fix them?
Actually it is not the answer :) But the solution I have used
export class ProfileStore {
#observable editing;
#observablt userProfile: UserProfile;
...
}
That's all - instead of using two stores, now there is one store, I happy that solution is working. I assume that error was that I forgot to write get at toJson. If in future I encounter same error and understand why it happened. I will try not to forget to update this answer.

push state object into state array in reactJS application

I have a store file which contains states. I defined user like this:
user: store.getState().user || { jobRecord: [] },
What I want is to push some job objects into user.jobRecord. The job object is defined like this:
job: store.getState().job || { title: '', company: '', start_date:
'', end_date: '' }
So first of all, I set some value into job object and then push it into user.jobRecord.
const joined = user && user.jobRecord;
store.setState({
user: {
...user,
jobRecord: [...joined, job],
},
});
By doing this, I get type error:
TypeError: joined is not iterable
I try this to set just one record in it:
jobRecord: [job],
but the result of jobRecord is:
[object Object]
Thank you a lot for considering my issue.
You are checking for falsey value in store.getState().user which is actually an object. Therefore it will always be true and jobRecord would never be filled and [...user] would give error as you are destructuring on empty object.
user: store.getState().user || { jobRecord: [] },
To avoid this issue use Object.keys(this.state.user).length to check if object is empty or not.
Working code below:-
import React from "react";
import ReactDOM from "react-dom";
class App extends React.Component {
state = {
job: {},
user: {}
}
componentDidMount () {
let user= Object.keys(this.state.user).length || { jobRecord: [] };
let job= this.state.job || {
title: '',
company: '',
start_date: '',
end_date: ''
};
const joined = user && user.jobRecord;
this.setState({
user: {
...user,
jobRecord: [...joined, job],
},
});
}
render () {
console.log('inside user',this.state.user)
return (
<div className="App">
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
It is not possible to iterate undefined value
const joined = user && user.jobRecord assigns undefined value to joined variable when user or user.jobRecord in undefined
To fix it, please use following code instead:
const joined = user && user.jobRecord || [];

Make a common function to store the local storage data

I am a newbie in react-native. I have a folder structure like below:
-screens
-page1.js
-page2.js
-page3.js
-page4.js
-App.js
In page1.js, I have a function to store data to localStorage
let obj = {
name: 'John Doe',
email: 'test#email.com',
city: 'Singapore'
}
AsyncStorage.setItem('user', JSON.stringify(obj));
Now I have to display these data in few of my other pages. This is my code.
class Page2 extends Component {
state = {
username: false
};
async componentDidMount() {
const usernameGet = await AsyncStorage.getItem('user');
let parsed = JSON.parse(usernameGet);
if (parsed) {
this.setState({
username: parsed.name,
email: parsed.email
});
} else {
this.setState({
username: false,
email: false
});
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.saved}>
{this.state.username}
</Text>
</View>
);
}
}
export default Page2;
This is how I display data in page2. I may need to show these in other page too.
I dont want to repeat these codes in each page.
Any suggestions how to do it in react-native?
You can extract the data you need to display into it's own component and re-use it in any page that you need to display it in.
Another option is to use a higher-order component, that way you can wrap it around any components that need the data and it'll be passed down as a prop.
You can make your Constant.js where you can put all your common required utils and constants, reusable anywhere n your app.
In your Constant.js:
export const USER_DATA = {
set: ({ user}) => {
localStorage.setItem('user', JSON.stringify(obj));
},
remove: () => {
localStorage.removeItem('user');
localStorage.removeItem('refresh_token');
},
get: () => ({
user: localStorage.getItem('user'),
}),
}
in your any component, you can import it and use like this :
import { USER_DATA } from './Constants';
let user = {
name: 'John Doe',
email: 'test#email.com',
city: 'Singapore'
}
// set LocalStorage
USER_DATA.set(user);
// get LocalStorage
USER_DATA.get().user
That's you can make Constant common file and reuse them anywhere to avoid writing redundant code.
Simplified Reusable approach of localStorage
export const localData = {
add(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
remove(key, value) {
localStorage.removeItem(key);
},
load(key) {
const stored = localStorage.getItem(key);
return stored == null ? undefined : JSON.parse(stored);
},
};
localData.add("user_name", "serialCoder")
console.log( "After set 👉", localData.load("user_name") )
localData.remove("user_name")
console.log( "After remove 👉", localData.load("user_name") )

Resources