React native issue : inserting an empty row - react-native

Testing some things in React and having some issues with some of my logic. I am trying to get value from inputs in a form then on submitting that form I want to take that object of input values and add them to my plant state. When I console log I get the state values but then the plant state is empty. Any help is appreciated.
Thank you
const [plant, setPlant] = useState();
const [TypeofPlant, setType] = useState('')
const [Phase, setPhase] = useState('')
const [Days, setDay] = useState(null)
const [Start, setStart] = useState(0)
const [End, setEnd] = useState(0)
const handleSubmit = async (e) => {
e.preventDefault()
setPlant({...plant,
TypeofPlant: TypeofPlant,
Phase: Phase,
Days: Days,
Start: Start,
End: End,
})
DataService.addNewPlant(plant).then(() => {
})
},
(error) => {
console.log(error)
}
);
DataService:
addNewPlant(data){
return http.post('/plants/add',data)
}

Try to console plant outside of DataService block.

The Response.json() method interface takes a Response stream and reads it to completion. It returns a promise which resolves with the result of parsing the body text as JSON.
Update the code like below
....
DataService.addNewPlant(data).then(res => {
const response = res.json();
setPlant({
TypeofPlant: response.data.TypeofPlant,
Phase: response.data.Phase,
Days: response.data.Days,
Start: response.data.Start,
End: response.data.End,
})
console.log(response.data);}
....

Related

fetch returns first empty array, after that it returns response

I'm making my final degree project and now I'm involved in the part to show towns on a map using data from a backend URL.
The problem is that fetch returns at first an empty array, and I need it to stay loading until the variable is a valid JSON.
const [isLoading, setLoading] = useState(true);
const [markers, setMarkers] = useState([]);
const getTowns = async () => {
try {
const response = await fetch(`${baseUrl}/towns`);
const json = await response.json();
setMarkers(json.data);
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};
useEffect(() => {
getTowns();
}, []);
Another question is: Why when I put a console.log('whatever') it appears more than one time on the console. Don't understand why
What I need is fetch to setLoading(false) only when response is a JSON, not an empty array
What you can do is add these 2 hooks to your code:
A state for the returned response (with initial value an empty array)
A useEffect which will set to false isLoading once the response state change value
const [response, setResponse] = useState([]);
const getTowns = async () => {
try {
setResponse(() => await fetch(`${baseUrl}/towns`));
const json = await response.json();
setMarkers(json.data);
} catch (error) {
console.error(error);
}
};
useEffect(() => {
setLoading(() => false);
}, [response]);
your code is fine you juste don't need the isLoading useState Hook. you can test with the value of markers
Why when I put a console.log('whatever') it appears more than one time on the console. Don't understand why
when the component first render getTowns runs in useEffect and since it updates the state the component renders again. learn more here about react component lifecycle
what I suggest is when you are returning your jsx you check if markers is still empty
const [markers, setMarkers] = useState('');
if(markers === ''){
return (<div>Loading...<div/>)
} else {
return(<>
.... what you need to return in you component
</>)
}

React native UseEffect and async issue

I'm trying to get a StoreKey from firestore (v9), and put it inside another collection of DB as a path.
for example, get storeKey (132, for example) and put inside
collection(db, 'store', storeKey, 'coffeeDB') to access specific sub collection. I put two function (1: getData (storeKey), 2: access to sub collection) into UseEffect so that it can run when it's mounted.
However, I found UseEffect runs twice, initial storeKey shows Array [], and the next run gets proper value which is 132. So, I'm having an error due to the first run.
I guess it's because the second function inside UseEffect does not wait for getData function to watch the data, but not too sure.
How can I resolve this issue??
const getData = async(setStoreKey, setName) => {
console.log('xxxx')
const auth = getAuth();
const user = auth.currentUser;
if(user !== null){
const email = user.email;
const UserInfo = await getDoc(doc(db, 'users', email));
if(UserInfo.exists()){
setStoreKey(UserInfo.data().storeKey)
setName(UserInfo.data().name);
}
else{
console.log('None')
}
return
}
}
T
const StockScreen = ({ navigation }) => {
const [storeKey, setStoreKey] = useState([]);
const [userName, setName] = useState([]);
const [coffeeStock, setCoffeeStock] = useState([]);
useEffect(() => {
getData(setStoreKey, setName);
const unsub = onSnapshot(collection(db, 'Store', storeKey, 'coffeeDB'), (snapshot) => {
setCoffeeStock(snapshot.docs.map((doc) => ({
id: doc.id,
data: doc.data(),
number: doc.data(),
})));
});
return unsub;
}, [storeKey]);
Just remove dependency from second argument in useEffect and pass blank array
useEffect(() => {
// your code
}, []);
It will run only once when your component is loaded. It is similar to componentDidMount of class component.
The reason your useEffect run twice is because your storeKey state changing in getData(setStoreKey, setName) function. So what you can do here if you want to call getData() function once is to declare it on a separate useEffect function like:
useEffect(() => {
getData(setStoreKey, setName); //call your getData function once
}, []);
And what I see is you need to update StoreKey every time for the unsub listener so with that above useEffect call another useEffect whenever the StoreKey dependency change like:
useEffect(() => {
getData(setStoreKey, setName); //call your getData function once
}, []);
useEffect(() => { //another useEffect whenever storeKey changes
const unsub = onSnapshot(collection(db, 'Store', storeKey, 'coffeeDB'), (snapshot) => {
setCoffeeStock(snapshot.docs.map((doc) => ({
id: doc.id,
data: doc.data(),
number: doc.data(),
})));
});
return unsub;
}, [storeKey]);
Hope this works for you.

problem with storing data from cache into useState in react native

const [loggedInData, setLoggedInData] = useState([]);
const getLoginFromCache = async() => {
try{
let logData = await AsyncStorage.getItem('#MyDish:loginData');
let parsed = await JSON.parse(logData);
console.log(parsed);
setLoggedInData(parsed);
}
catch(error){
console.log(error);
}
}
getLoginFromCache()
console.log(loggedInData);
the result console.log(loggedInData) is always empty. whereas when i console.log(parsed) doesn't return empty
Use redux persist for store data on cache and to state.
https://www.npmjs.com/package/redux-persist
React set state is async, so console.log(loggedInData); will always print the initializtion state of loggedInData, in this case this state is an empty array
Try to wrap your getLoginFromCache function inside an useEffect like this:
const [loggedInData, setLoggedInData] = useState([]);
useEffect(() => {
const getLoginFromCache = async() => {
try{
let logData = await AsyncStorage.getItem('#MyDish:loginData');
let parsed = await JSON.parse(logData);
console.log(parsed);
setLoggedInData(parsed);
}
catch(error){
console.log(error);
}
}
getLoginFromCache()
}, [])
and if you want tracking your loggedInData state, you can use another useEffect to log that one:
useEffect(() => console.log(loggedInData),[loggedInData])

how to handle the return values from reducer, inside a functional component

This may be a basic question, but I'm new to React Native and stuck here.
My code pasted below. reducer and functional component. I want to capture the response returned from reducer.
reducer.js
export const ActivationCenterReducer = (
state = INIT_KIT_STATE,
{ type, payload = {} }
) => {
switch (type) {
case 'KIT_ACTIVATION_SUCCESS_DATA': {
const { message, response_code, apiLoading, apiError } = payload;
return {
...state,
apiLoading: apiLoading,
apiError: apiError,
message: message,
response_code: response_code
};
}
// ...
}
// ...
};
Functional Component class:
const kitActivationCenter = ({ route, navigation }) => {
const response_code = useSelector(
store => store.kitActivationCenter.response_code
);
const handleKitActivation = () => {
/*This will call the validation() inside action.js and that follows the reducer.js file. where reducer.js file returning the values on success response. but I am not able to access that response_code returned from reducer.
How to save the response_code from the below dispatch function.*/
dispatch(Validation(locator, pin));
if (response_code === 200) {
// should navigate to the next screen
}
};
};
My question is how to capture the returned response_code from reducer.
I'm able to navigate to the next screen on clicking the submit button couple of times.I notice that first time when the dispatch function is called, the state of the response_code is not updating , hence the response_code != 200.
I want a way to capture the response and assign to variable.
Thanks in advance.
You are probably looking at the old value of response_code in your handleKitActivation.
const kitActivationCenter = ({ route, navigation }) => {
const response_code = useSelector(
store => store.kitActivationCenter.response_code
);
const handleKitActivation = () => {
dispatch(Validation(locator, pin));
// HERE the response_code does not have result value
// of your calling dispatch(Validation(locator, pin)) above yet
if (response_code === 200) {
// should navigate to the next screen
}
};
};
I suggest to move your response_code hanfling to the useEffect:
const kitActivationCenter = ({ route, navigation }) => {
const response_code = useSelector(
store => store.kitActivationCenter.response_code
);
// this effect will run whenever your response_code changes
useEffect(() => {
if (response_code === 200) {
// should navigate to the next screen
}
}, [response_code]);
const handleKitActivation = () => {
dispatch(Validation(locator, pin));
};
};

redux-thunk: actions are not dispatching

I am trying to build an app in react native that is suppose to take take two inputs by a user and then make a query to an api and get information about the two inputs. I have been having trouble with redux and redux-thunk and specifically with async actions.
This is the code in my app that i am specifically having trouble with
export const fetchData = url => {
console.log("start Fetching");
return async dispatch => { // this is where the problem is
dispatch(fetchingRequest());
try {
const response = await fetch("https://randomuser.me/api/?results=10");
const json = await response.text();
if (response.ok) {
dispatch(fetchingSuccess(json));
console.log("JSON", json);
} else {
console.log("fetch did not resolve");
}
} catch (error) {
dispatch(fetchingFailure(error));
}
};
console.log("Fetched data");
};
Upon debugging the function, I have ended with finding that when the fetchData function is called the function will execute but the async dispatch that is being returned has undefined behavior.
The output in the debugger when the function is called should be
start Fetching
JSON file information/Error
but the output in the debugger is actually
start Fetching
This is the function in which fetchData is called in
_onPress = () => {
let url = "https://randomuser.me/api/?results=10";
fetchData(url);
console.log("should have fetched");
};
this is the mapDispatchToProps function that I have added. The problem is i do not know what to add inside the function.
const mapStatetoDispatch = (url, dispatch) => {
return {dispatch(fetchData(url))}; // do not know what to place in body of function
};
i have connected it in the component with
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
these are the action creators that I import, if needed
import {
fetchingSuccess,
fetchingRequest,
fetchingFailure,
fetchData
} from "../data/redux/actions/appActions.js";
Assuming you have added redux-thunk as a middleware, it looks like the errors are here:
_onPress = () => {
const { fetchData } = this.props;
let url = "https://randomuser.me/api/?results=10";
fetchData(url);
console.log("should have fetched");
};
and
const mapStatetoDispatch = dispatch => ({
fetchData: url => dispatch(fetchData(url)),
}};