AsyncStorage & Drawer render always null - javascript

I have a login screen with a button remember me and when I connect, I would like to store this info in asynsctorage like this:
if (this.isFormValid()) {
AccountService.login(login, password)
.promise.then(body => {
console.log('onLoginClick -> body', body)
Keyboard.dismiss()
AsyncStorage.setItem('login', login)
if (this.state.isRememberMeSelected) {
console.log("i'm in the storage !")
AsyncStorage.multiSet([['login', login], ['password',
password], ['isRememberMeSelected', '1']])
} else {
AsyncStorage.multiSet([['login', ''][('password', '')],
['isRememberMeSelected', '0']])
}
when I go back to my Drawer, I try to read the storage and get my value "isRememberMeSelected" :
async componentDidMount() {
// await AsyncStorage.getItem('login').then(value => {
// console.log('DrawerLogin', value)
// //this.setState({login: value})
// })
// await AsyncStorage.getItem('password').then(value => {
// console.log('DrawerPassword', value)
// //this.setState({password: value})
// })
await AsyncStorage.getItem('isRememberMeSelected').then(value => {
console.log('DrawerIsRememberMeSelected', value)
this.setState({isRememberMeSelected: value})
})
// await AsyncStorage.getAllKeys((err, keys) => {
// console.log(' Allkeys', keys)
// })
}
in me drawer, I check the value "isRememberMeSelected" to remove some items:
StorageMultiRemove = async () => {
try {
await AsyncStorage.multiRemove(['refreshToken',
'stripeCustomerId', 'token'], err => {
console.log(' Dans multiRemove Error', err)
})
} catch (error) {
// Error saving data
}
}
isRememberMeSelected === '1' ? this.StorageMultiRemove() :
AsyncStorage.clear()
when I go back in my drawer, this value and always null EXCEPT if I leave the app and relaunch ... there everything is well set....
I fit well in my condition (the one before doing my setItem) ...
I would like to record this data in asynStorage, return to my drawer and have these values ​​available

You could add a variable that will change when asyncstorage has been fetched
class Myform extends React.Component {
state = {
loading: true
}
then in component did mount update the state
componentDidMount() {
await AsyncStorage.getItem('isRememberMeSelected').then(value => {
console.log('DrawerIsRememberMeSelected', value)
this.setState({
isRememberMeSelected: value,
loading: false
})
})
}
and in render
render() {
if(loading) return; // could return loading spinner or something
}

Related

How to update the FlatList dynamically in react native?

Initially loading data from API to FlatList using setState and it loaded perfectly. But I have to perform some actions like create, update & delete of FlatList row. When I try to add new data to the FlatList, the data is not rendered in FlatList with an updated one, but In API it's updated.
How to re-render the flatlist after updating to the API and load the new data to FLatList?
Here is my code:
constructor(props) {
super(props);
this.state = {
faqs: [],
}
this.loadFaq();
};
To load the data to FlatList from the API:
loadFaq = async () => {
let resp = await this.props.getFaqGroup();
if (resp.faqs) {
console.log(resp.faqs)
this.setState({
faqs: resp.faqs,
// refresh: !this.state.refresh
})
}
};
To add new data to API:
createFaqGroup = async (name) => {
let resp = await this.props.createFaqGroup(name);
// console.log("resp", resp)
// this.setState({
// refresh: !this.state.refresh
// })
// this.forceUpdate();
this.closePanel();
}
FlatList code:
{this.state.faqs && <FlatList
extraData={this.state.faqs}
horizontal={false}
data={this.state.faqs}
contentContainerStyle={{ paddingBottom: 75 }}
renderItem={({ item: faqs }) => {
return <Card gotoQuestionList={this.gotoQuestionList} key={faqs._id} faqs={faqs} openPanel={(selectedFaq) => this.openPanel({ name: selectedFaq.name, id: selectedFaq._id })} deletePanel={(selectedFaq) => this.deletePanel({ name: selectedFaq.name, id: selectedFaq._id, isPublished: selectedFaq.isPublished })}></Card>
}
}
keyExtractor={(item) => item._id}
/>}
this.props.createFaqGroup function code:
export const createFaqGroup = (name) => {
const options = {
method: 'POST',
data: { "name": name },
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${store.getState().auth.info.token}`
}
};
return async (dispatch) => {
console.log('url::', options)
try {
let url = `${config.baseUrl}${config.faqUrl}`;
let resp = await axios(url, options);
console.log(resp.data)
return resp && resp.data ? resp.data : null;
} catch (error) {
alert(error)
if (error.response && error.response.status === 401) {
dispatch({
type: type.ERROR,
data: error.response.data
});
} else {
dispatch({
type: type.CREATE_FAQ_GROUP_ERROR,
error: error.message
});
}
}
};
}
Any help much appreciated pls...
Flatlist will update automatically when you set your state i.e by using this.setState() function, it means whenever any changes made to your state variable it will rerender your flatlist. if you still face the same problem remove your this.state.faqs && part, this looks unnecessary because there is no need to check if you are passing the empty array to faltlist or not, flatlist allows you to pas empty array as well, it will not give you any error.
I think you should load data again, after you add them, so you can modify your function createFaqGroup like this:
createFaqGroup = async (name) => {
let resp = await this.props.createFaqGroup(name);
this.loadFaq();
this.closePanel();
}
Try this:
createFaqGroup = async (name) => {
let resp = await this.props.createFaqGroup(name);
this.setState({faqs: [...this.state.faqs, name]})
this.closePanel();
}

sync button state in realtime using APIs in React Js

So I have two APIs one is Post API Which I linked to my Toggle button, whenever button is clicked it sends 1 or 0 value to Post API and I have other GET API from where I'm getting the state of value which I'm using to the same button to check weather it is 0 or 1.
The problem is my code works but it can't get sync because when I click button it updates state value through post API but previous GET Request Makes it again on previous state. so on render button flickers a couple of times and then get settled. Code is given below. Any solution will be highly appreciated. Thanks in advance.
P.S. on componentDidMount() I'm Calling the GET Request and handleChange is linked to the button
class Test extends React. Component {
constructor(props) {
super(props);
this. State = {
checked: false,
value:bool,
}
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
this.intervalId = setInterval(()=> this.loadData(), 1000);
this.loadData();
}
componentWillUnmount() {
clearInterval(this.intervalId);
}
async loadData() {
const headers = {
'api-key': 'key',
};
try {
const response = await fetch('url', { headers })
const json = await response.json();
const valueUp = json.data ;
if( valueUp ===1 ) {
this.setState({value: valueUp, checked: true})
}
else if (valueUp === 0) {
this.setState({value: valueUp, checked: false})
}
}
catch (err){ console.log(err);}
}
handleChange() {
if (this.state.value === 0) {
this.setState({ value:1, checked: true }, () => {
this.afterSetStateFinished();
})
}
else if (this.state.value === 1) {
this.setState({ value:0, checked: false }, () => {
this.afterSetStateFinished();
})
}
};
afterSetStateFinished(){
const article = {
"body": this.state.value
}
const headers = {
'api-key': 'key',
};
axios.post('url', article, { headers })
.then(function(response) {console.log(response);
})
}

Checkbox with true or false value throwing error in React Class Component?

I have two checkboxes that were working previously but are now throwing an error. These checkboxes simply return a true or false in the form, which is submitted to the Firestore backend. These were working fine recently until so other changes were make.
The error in question is
TypeError: Cannot create property 'cash' on boolean 'false'
This is triggered whenever the checkbox is clicked. I am using a
changeStoreData() action to update the FireStore, this action is called all throughout my app in order to update the users information
This is my state setup
constructor(props) {
super(props);
this.state = {
currency: "USD",
tax_rate: "8.00",
prices_include_tax: false,
payment_types: {
cash: false,
credit: false
}
};
}
Theses are the buttons in question
handleCash = () => {
this.setState(state => {
var newData = state.payment_types;
newData.cash = !state.payment_types.cash;
return {
payment_types: newData
};
});
};
handleCredit = () => {
this.setState(state => {
var newData = state.payment_types;
newData.credit = !state.payment_types.credit;
return {
payment_types: newData
};
});
};
This is the onSubmit function calling the changeStoreData() function
handlePaymentInfoSub = e => {
e.preventDefault();
this.setState(state => {
changeStoreData(state);
// I know this needs to be more explicit
// Other places in my app this is called changeStoreData({DBvalue:
// stateValue}) but I am not sure how to do this with nested values
return state;
});
};
and finally here is the changeStore function itself from the actions file
export function changeStoreData(data) {
let currentState = store.getState();
let id = currentState.currentStore.id;
console.log(data);
firestoreDb
.collection("users")
.doc(currentState.uid)
.collection("stores")
.doc(id)
.update(data)
.then(
store.dispatch({
type: UPDATE_STORE_DATA,
data: data
})
)
.catch(err => {
console.log(err);
});
}
The error given is
TypeError: Cannot create property 'cash' on boolean 'false'

Javascript function first execute and return value, before proceedng

I am writing a React application where I first want to make sure that both of my JWT token are set prior continuing the application (componentDidMount lifecycle hook). I used a callback to make certain that the second function awaits the first function. but for some reason the value is not in my localstorage yet. I cannot use redux for this, as the first two calls that I am fetching are user images.
All hints/advise is welcome. Thanks.
app.js
componentWillMount() {
function firstFunction(_callback){
acquireToken();
acquireGraphToken();
_callback();
}
function secondFunction(){
firstFunction(function() {
console.log('huzzah, I\'m done!');
});
}
secondFunction();
}
ADAL.JS (Which handles my token requests.)
import { AuthenticationContext, adalFetch } from 'react-adal';
const adalConfig = {
instance: 'https://login.microsoftonline.com/',
clientId: '*******',
extraQueryParameter: 'nux=1',
endpoints: {
graphApi: 'https://graph.microsoft.com',
oneApi: 'https://one365demo.onmicrosoft.com/b153b2*********-3f1d0cf658f5'
},
postLogoutRedirectUri: window.location.origin,
redirectUri: window.location.origin,
cacheLocation: 'localStorage'
};
export const authContext = new AuthenticationContext(adalConfig);
export const adalGraphFetch = (fetch, url, options) =>
adalFetch(authContext, adalConfig.endpoints.graphApi, fetch, url, options);
export const adalOneApiFetch = (fetch, url, options) =>
adalFetch(authContext, adalConfig.endpoints.oneApi, fetch, url, options);
export const getToken = () => {
return authContext.getCachedToken(authContext.config.clientId);
};
export const getGraphToken = () => {
return authContext.getCachedToken('https://graph.microsoft.com');
};
export const acquireGraphToken = () => {
authContext.acquireToken(adalConfig.endpoints.graphApi, (message, token, msg) => {
console.log('graph token', token);
return token;
})
return null;
}
export const acquireToken = () => {
authContext.acquireToken(adalConfig.endpoints.oneApi, (message, token, msg) => {
console.log('the token', token);
return token;
})
return null;
}
The render() method evaluates once in a very early moment, before componentWillMount(). Then it is reevaluated (in principle) every time the component state is changed via the setState method.
What I usually do is to mark in the component's state when the initialization is completed, and check for this mark in the render() method. In your example:
componentWillMount() {
function firstFunction(_callback){
acquireToken();
acquireGraphToken();
_callback();
}
function secondFunction(){
firstFunction(function() {
console.log('huzzah, I\'m done!');
this.setState({dataIsReady: true})
});
}
secondFunction();
}
render() {
if (this.state.dataIsReady) {
// render the actual app
} else {
// render some "Loading ..." message
}
}
Hope it helps - Carlos
You should create a value in the state to track your preliminary function completion. Just change the value, and then have the component load as normal.
e.g.
class App extends React.Component {
state = { shouldLoad: false }
firstFunction() {
//Execute your functions here then...
//Set state when complete...
this.setState({ shouldLoad: true });
}
render() {
const {shouldLoad} = this.state;
return (
<div>
{shouldLoad === true && (
<p>Load your content here</p>
)}
</div>
);
}
}

Getting backend data in front reactJS

I am getting data from the backend to display it in the font like this
componentDidMount() {
const response = this.props.store.privateImputationData;
console.log(response);
}
It displays null in the console, now if i do a setTimeout it works!
componentDidMount() {
setTimeOut(() => {
const response = this.props.store.privateImputationData;
console.log(response);
}, 500);
}
This how i m getting data from my store:
#computed get ImputationData() {
return this.privateImputationData || {};
}
loadImputation = (diplayedImputations) => {
HttpClient.postJSON(this.apiDataUrl, diplayedImputations).then((result) => {
this.privateImputationData = result;
this.loadAdditionalData();
});
}
How can i do it without setTimeout?
You can use the state object: State and Lifecycle. Whenever the state changes, whatever component uses it, get's updated too.
this.state = {privateImputationData: null} //or some default
So in your code:
#computed get ImputationData() {
return this.privateImputationData || {};
}
loadImputation = (diplayedImputations) => {
HttpClient.postJSON(this.apiDataUrl, diplayedImputations).then((result) => {
this.setState({privateImputationData: result});
this.loadAdditionalData();
});
}
To use the value:
this.state.privateImputationData;

Categories

Resources