I'm using Redux-Saga in a React Native app. When I get the authentication token back from the server, how do I save it to local storage?
I tried using
await AsyncStorage.setItem("token", token);
but React Native complained and said await
was a reserved word.
Am I misunderstanding something? Is the saga code not where I should be doing this?
Here is my code
function* loginFlow(action) {
try {
let username = action.username;
let password = action.password;
const response = yield call(getUser, username, password);
let token = response.headers.get("access-token");
const result = yield response.json();
if (token) {
console.log("success: ", token);
yield put({ type: LOGIN_SUCCESS, result });
} else {
if (result.error) {
yield put({ type: LOGIN_FAILURE, error: result.error });
}
}
} catch (e) {
yield put({ type: LOGIN_FAILURE, error: e.message });
console.log("error", e);
}
}
Edit: Here is the getUser function:
const getUser = (username, password) => {
return fetch(`${apiURL}/${apiVersion}/${apiType}/${apiEndpoint_auth}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
email: username,
password: password
})
});
};
This is how i managed to store token inside redux-saga generator.
function* loginFlow(email, password) {
try {
// get your token
const token = yield call(loginApi, email, password);
// store token to local storage
yield call(storeToken, token);
yield put({ type: LOGIN_SUCCESS });
} catch (error) {
yield put({ type: LOGIN_ERROR, error });
}
}
function loginApi(email, password) {
return fetch('https://yourApiUrl', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
})
.then(response => response.json())
.then(json => json)
.catch((error) => {
throw error;
});
}
async function storeToken(token) {
try {
await AsyncStorage.setItem('token', token);
} catch (error) {
console.log('AsyncStorage error during token store:', error);
}
}
Note: Store your token before you dispatch your LOGIN_SUCCESS action. So that you will get your token in React Component by re-rendering made by LOGIC_SUCCESS action.
Since each method of the AsyncStorage API returns a Promise object, you could use redux-saga call(fn, ...args)
function.
From the documentation of call(fn, ...args)
, you could use it on a normal function that returns a Promise as a result.
Creates an Effect description that instructs the middleware to call the function fn with args as arguments.
fn: Function - A Generator function, or normal function which either returns a Promise as result, or any other value.
args: Array - An array of values to be passed as arguments to fn
In this case, we could use yield call(fn, ...args)
this way:
yield call(AsyncStorage.setItem, "token", token)
This would have the same effect as await
, where it would block the execution until the Promise is resolved / rejected.
Full code snippet with minor comments:
function* loginFlow(action) {
try {
let username = action.username;
let password = action.password;
const response = yield call(getUser, username, password);
let token = response.headers.get("access-token");
const result = yield response.json();
if (token) {
console.log("success: ", token);
// Wait / block until the Promise is resolved
yield call(AsyncStorage.setItem, "token", token);
// Will be only executed once the previous line have been resolved
yield put({ type: LOGIN_SUCCESS, result });
} else {
if (result.error) {
yield put({ type: LOGIN_FAILURE, error: result.error });
}
}
} catch (e) {
yield put({ type: LOGIN_FAILURE, error: e.message });
console.log("error", e);
}
}
Reference:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With