Redux работает только после принудительного обновления sh (с контекстом / провайдером) - PullRequest
0 голосов
/ 12 февраля 2020

Итак, у меня проблема с реакт-редуксом. У меня есть экран входа в систему, где люди могут ввести свое имя пользователя и пароль. Эти учетные данные отправляются на сервер, и если они верны, клиенту отправляется токен авторизации. Я храню этот токен аутентификации в Redux. Чтобы «визуализировать» мою проблему, я добавил (упрощенный) код ниже. Ниже приведено более подробное объяснение кода.

// folder structure
// ----------------
// - App.js
// - screens/
//     - SignIn.js
//     - Main.js
// - navigators/
//     - Stack.js (stack navigator for SignIn.js and Main.js)
// - store/
//     - actions/
//         - Auth.js
// - providers/
//     - Auth.js


// App.js (simplified)
// -------------------
...
import { AuthProvider } from './providers/Auth'
import StackNavigator from './navigators/Stack'
...
const App = () => {
    return (
        <Provider store={store}>
            <AuthProvider>
                <StackNavigator />
            </AuthProvider>
        </Provider>
}


// screens/SignIn.js (simplified)
// ------------------------------

...
import { saveAuthToken } from '../store/actions/Auth'
...
let req = await fetch('URL_TO_SERVER', {
    method: 'POST',
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        username,
        password
    }
let status = req.status
let res = await req.json()
if (status === 200) {
    // everything is ok
    dispatch(saveAuthToken(res.authToken))
    props.navigation.navigate('Main')
}

// screens/Main.js (simplified)
// ----------------------------

...
import { AuthContext } from '../providers/Auth'
import { deleteAuthToken } from '../store/actions/Auth'
...
const { token, state } = useContext(AuthContext)
...
useEffect(() => {
    if (state === 'unauthenticated') {
        dispatch(deleteAuthToken())
        props.navigation.navigate('SignIn')
    }
}, [state])

// providers/Auth.js (simplified)
// ------------------------------

...
import React, { createContext } from 'react'
import { useDispatch, useSelector } from 'react-redux'
...
export const AuthContext = createContext()
export const AuthProvider = props => {
    const dispatch = useDispatch()
    const [token, setToken] = useState(useSelector(state => state.token.auth))
    const [state, setState] = useState('pending')
    const authenticateHandler = async () => {
        // do stuff with a fetch to the server
        // to validate the auth token
        // let's say the state of the auth token is
        // reflected in the status code of the response
        let req = await fetch(...)
        let status = req.status
        let res = await req.json()
        if (status === 400) {
            setState('expired')
        }
        if (status === 200) {
            setState('authenticated')
        }
    }
    useEffect(() => {
        if (token !== null) {
            authenticateHandler()
        } else {
            setState('unauthenticated')
        }
    }, [state])
    return (
        <AuthContext.Provider value={{ token, state }}>
            {props.children}
        </AuthContext.Provider>
    )
}

Когда пользователь успешно выполняет вход (экран) Вход , токен аутентификации сохраняется в редуксе через dispatch(saveAuthToken()). После этого пользователь перенаправляется на (экран) Main . Здесь проблема возникает! Когда пользователь отправляется на (экран) Main , его состояние все еще «не аутентифицировано», потому что useSelector(state => state.token.auth) возвращает null в первый раз. Только когда я вручную обновляю sh код, токен успешно извлекается из резервной копии и состояние изменяется на «authenticated». Так что проблема в том, что я не могу проверить «реальное» состояние пользователя ( перед проверкой sh. Поскольку я удаляю токен (экран) Main , когда пользователь не прошел проверку подлинности, я застреваю в бесконечном l oop между SignIn и Main.

Может кто-нибудь помочь мне с этой проблемой

1 Ответ

1 голос
/ 13 февраля 2020

С помощью редукса вы можете использовать mapStateToProps, чтобы перенести значение редуктора в ваш компонент. Я предполагаю, что вы уже делаете это, но если нет , прочитайте его .

С этим у вас есть доступ к значению, и как только он изменится, ваш компонент обновится. Вы смотрите это обновление, и если в нем есть новое значение токена, вы сохраняете его в своем состоянии.

С перехватами это будет сделано с useEffect. Наблюдается второй аргумент, и функция запускается при его изменении, поэтому вы поместите туда значение сопоставленного реквизита.

Без хуков вы будете наблюдать за ним в componentDidUpdate, который получает старые реквизиты в качестве первого аргумента, что позволяет вам проверять oldProps.myMappedReduxValue !== this.props.myMappedReduxValue.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...