I have my store using the Context API to create a user, where there are two screens for completing the registration. The first screen has several input fields that I control with React Hook Form, and when I enter all the data, I navigate to the other screen and fill in 2 more inputs, one being a checkbox with several options.
On the first screen, I can get all the information from the user, and on the second screen, I can get only the values of the checked boxes, and the location input that I have, it cannot insert into the state of my Context API.
src/store/CreatePersonalAccount/index.tsx
import { createContext, useReducer } from 'react'
import { reducer } from './reducer'
export const initialState: PersonalAccount = {
avatar: '',
name: '',
email: '',
password: '',
location: '',
occupationCategory: '',
occupationSubcategories: []
}
export const CreatePersonalAccountContext = createContext<
IContext<PersonalAccount>
>({
state: initialState,
dispatch: () => {}
})
export const CreatePersonalAccountContextProvider: React.FC = ({
children
}) => {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<CreatePersonalAccountContext.Provider value={{ state, dispatch }}>
{children}
</CreatePersonalAccountContext.Provider>
)
}
CreatePersonalAccount/action.ts
export enum CreatePersonalAccountActions {
SET_CREATE_PERSONAL_ACCOUNT = 'SET_CREATE_PERSONAL_ACCOUNT',
}
export const setPersonalAccount = (payload: Partial<PersonalAccount>) => {
return {
type: CreatePersonalAccountActions.SET_CREATE_PERSONAL_ACCOUNT,
payload
}
}
CreatePersonalAccount/reducer.ts
import { initialState } from './index'
import { CreatePersonalAccountActions as ActionTypes } from './action'
export const reducer = (state: PersonalAccount, action: IAction) => {
switch (action.type) {
case ActionTypes.SET_CREATE_PERSONAL_ACCOUNT:
return {
...state,
...action.payload
}
case ActionTypes.RESET:
return {
...initialState
}
default:
return state
}
}
In my user creation routes, I have hooks that can be used both on the first screen and on the second screen.
import { useContext } from 'react'
import { CreatePersonalAccountContext } from 'store/CreatePersonalAccount'
import {
setPersonalAccount,
resetPersonalAccount
} from 'store/CreatePersonalAccount/action'
export function usePersonalAccount() {
const { state, dispatch } = useContext(CreatePersonalAccountContext)
const setPersonalInformation = (state: PersonalAccountInformation) =>
dispatch(setPersonalAccount(state))
const setPersonalLocation = (location: string) =>
dispatch(setPersonalAccount({ location }))
const setPersonalOccupation = (
params: Partial<
Pick<PersonalAccount, 'occupationCategory' | 'occupationSubcategories'>
>
) => dispatch(setPersonalAccount(params))
const clearPersonalAccount = () => dispatch(resetPersonalAccount())
const submit = () => {
console.log('Enviar pra API', state)
}
return {
state,
submit,
setPersonalLocation,
clearPersonalAccount,
setPersonalOccupation,
setPersonalInformation
}
}
The setPersonalInformation function is used on the first screen with the user information, and the other functions setPersonalLocation and setPersonalOccupation are used on the second screen of the user information, the problem is the setPersonalLocation function that cannot update the state with the new location property.
This function below is the function I use in the first info screen, and it works correctly, updating the avatar, name, document, email, password fields.
SignUp/PersonalAccount/PersonalInformation/index.tsx
...
function handleRegisterPersonal(data: PersonalAccountInformation) {
const personalInformationData = {
...data,
avatar: image
}
setPersonalInformation(personalInformationData)
navigation.navigate('PersonalLocationAndOccupation')
}
...
And on the screen where I would like to update the location property is the function below.
SignUp/PersonalAccount/PersonalLocationAndOccupation
function registerPersonalAccountForm({ location }: PersonalAccountLocation) {
setPersonalLocation(location)
navigation.navigate('Welcome')
}
And my final state is this, but without the location property assigned
Object {
"avatar": "file:///Users/vagnerwentz/Library/Developer/CoreSimulator/Devices/BCB82E0B-A81E-495A-9917-80C315CEE735/data/Containers/Data/Application/FB8A6B2E-3F8F-4EBE-9AC0-128BBC80A84E/Library/Caches/ExponentExperienceData/%2540anonymous%252FPlugApp0800-fe3f8358-2821-44a3-a206-d0e1909b03e0/ImagePicker/FF615EB9-E385-4397-9198-E49FE6CD8CE4.jpg",
"documentation": "1234567890",
"email": "email@email.com",
"location": "",
"name": "John Doe",
"occupationCategory": "Developer",
"occupationSubcategories": Array [
Object {
"id": "frontend",
"title": "Front-end",
},
Object {
"id": "backend",
"title": "Back-end",
},
],
"password": "1234567890",
}
I've already tried to put it in the property inside the useForm, assign the context field, with my Context, but without success, I also tried to put a setTimeout to simulate an asynchronous call, and I didn't succeed either.