React, logowanie odczyt globalnego stanu

1

Witam. Jak zorganizować dobrze funkcjonalność logowania?. Mam kod w komponencie funkcyjnym:

const dispatch=useDispatch()
    const [isLoading, setIsLoading] = useState(false)
    const userState = useSelector<LoginUserState, LoginUserState>((state : any) => state.loginReducer);
    
    React.useMemo(()=>
    {
        if (!userState.loggedIn && userState.error.length>0) {
            message.error(userState.error)
        }
    },[userState])

    const handleSubmit = (e:FormEvent):void => {

            e.preventDefault();
           
            props.form.validateFields(async (err, values)=>{
                if (!err)
                {
                   setIsLoading(true); 
                   let result = await LoginCommand(values.username, values.password);                   
                   await dispatch(result)   
                   setIsLoading(false);  
                }
            })
    }

czyli mamy wywołanie handleSubmit w momencie gdy nacisnę zaloguj. Walidacja formularza. Jeśli nie ma błędów setIsLoading powoduje kręcące się kółeczko na przycisku. potem wywołuje metodę LoginCommand, (tam jest fetch itp) i w zależności od wyniku fetch'a zwraca odpowiedni obiekt:

export const LOGIN_SUCCESS='LOGIN_SUCCESS'
export const LOGIN_FAILURE='LOGIN_FAILURE'

interface LoginSuccessAction {
    type: typeof LOGIN_SUCCESS,
    payload: string
}

interface LoginFailureAction {
    type: typeof LOGIN_FAILURE
    error: string
}

export type LoginActionTypes = LoginSuccessAction | LoginFailureAction

potem robię dispatch w celu zaaktualizowania stanu globalnego.

zaraz po dispatch chciałbym odczytać ten stan globalny no i zrobić jakieś przekierowanie do głównej aplikacji. Ale okazuje się, że będąc jeszcze w zdarzeniu handleSubmit nie widzę, zaaktualizowanego stanu userState.
Jedyne rozwiązanie jakie mi zadziałało to useMemo. Na obecną chwilę to jest tylko wyświetlenie komunikatu z błędem logowania. Jak zorganizować dobrze kod, żeby to chodź trochę profesjonalnie? :)

0

Dołączam się do pytania, bo mam podobny problem. Jedyne rozwiązanie, jakie znalazłem, to przekazywanie callbacków do kreatorów akcji. Na StackOverflow Dan Abramov pisze, że można tak robić, a zatem można tak robić. :D

Jeśli chodzi o przekierowywanie, to w dokumentacji React Router, piszą, że The solution here is simply to include the history object (provided to all route components) in the payload of the action, and your async handler can use this to navigate when appropriate.

Ale może ktoś bardziej doświadczony się wypowie.

1

Też myślałem o callbacku ale ostatecznie zdecydowałem się na takie rozwiązanie:

const handleCommandResult = async (result:LoginActionTypes): Promise<void> => {

          if (result.type === LOGIN_SUCCESS) {
              history.push("/app/clients")
          }
          else {
            message.error(result.error);
          }
    }

    const handleSubmit = (e:FormEvent):void => {

            e.preventDefault();
           
            props.form.validateFields(async (err, values)=>{
                if (!err)
                {
                   setIsLoading(true); 
                   let result = await LoginCommand(values.username, values.password);                   
                   dispatch(result)
                   handleCommandResult(result);   
                   setIsLoading(false);  
                }
            })
    }
0

Hmm, tylko że takie rozwiązanie wydaje się być wbrew idei, dla której nasz prorok Dan Abramov stworzył "bibliotekę" redux-thunk :D Na StackOverflow pisze o zaletach płynących z jej korzystania. Wydaje mi się, że najlepiej byłoby po prostu zwrócić Promise, a potem w komponencie zrobić then/catch albo try/catch, tak jak to pokazują w dokumentacji.

0

Może i lepiej, nie wiem. Wiem za to, że co czytam jakiś blog jak tych mechanizmów używać, tym większy mam mętlik w głowie. Każdy pisze inaczej. A niektóre rozwiązania są tak napisane, że muszę się długo zastanawiać o co tam chodzi. Napiszę sam to przynajmniej za miesiąc nie zapomnę jak to działa

1

Mam tak samo. Ekosystem Reacta to jakaś porażka. Większość tutoriali, jakie czytam, pokazuje proste, wyidealizowane przypadki zamiast jakieś przykłady real-world. Do tego później trzeba połączyć ten kod z bloga z X bibliotekami tak, aby to miało ręce i nogi. Nie pomaga fakt, że każdy używa czegoś innego. Nie dziwie się, że ludzie wybierają opcję backend-only. Jedyna nadzieja w Blazorze, ale to raczej odległa przyszłość...

1

Myślałem o czymś takim:

// thunk
const getData = () => async dispatch => {
    const response = await callApi()
    dispatch(dataFetched(response.data))
}
// komponent
try {
    setIsLoading(true)
    await getData()
    // operacja się powiodła, zrób coś tutaj
} catch (e) {
    setError(e)
} finally {
    setIsLoading(false)
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1