I am working on a screen which takes data through route.params.
const {
prompt,
isUpscaling,
imageToBeUpscaled,
useDefaultPrompts = true,
isChallenge = false,
challengeData = {},
isCommunityPage,
} = route.params;
When navigating to this page, the params first being passed are actually the previous values. However, upon saving the file(thereby updating the state) the expected params load in.
I am using the params' data in a focusEffect function:
useFocusEffect(
useCallback(() => {
setIsLoading(true);
setSafeAreaBackgroundColor("#1a1a1a");
generateImage();
}, [])
);
However, the original data being passed to this function are the old values. In short, the values being used are the previous route.params value from an old screen and not the new ones being passed in. The new params are being passed in but (I'm assuming) are not loading before the useFocusEffect is called. This results in the function using old data rather than new data.
How can I have the route.params data be updated when used in the useFocusEffect function?
Related
In my react-native project, I have one screen needs to query data from backend, then, there are some code using the backend returned data should only be run once when the screen mounted. This is what I did (I am using [react-query][1] for data fetching from backend):
const MyScreen = ()=> {
// fetch data from backend or cache, just think this code gets data from backend if you don't know react-query
const {status, data, error} = useQuery(['get-my-data'], httpClient.fetchData);
// these code only need to run once when screen mounted, that's why I use useEffect hook.
useEffect(() => {
// check data
console.log(`data: ${JSON.stringify(data)}`);
// a function to process data
const processedData = processeData(data);
return () => {
console.log('Screen did unmount');
};
}, []);
return (<View>
{/* I need to show processed data here, but the processedData is scoped in useEffect hook & I need to have the process data function in useEffect since only need it to be run once */}
</View>)
}
My issue:
The code in useEffect only run once when the screen is mounted, however at that point the query above returns data with value undefined until re-render happens, the data is then fetched however code inside useEffect will never run again though the data is fetched when re-rendered . How can I get rid of this issue?
without knowing what exactly is httpClient.fetchData, I can only assume it will return a res.json. you should be able to do something like this.
const {status, data, error} = useQuery(['get-my-data'], httpClient.fetchData).then((res)=>{processData(res)});
With this, data should now become the processedData in your example.
I have two hooks:
const dispatch = useDispatch();
const response = useSelector(state => state.responseData);
And submit function:
const submit = () => {
dispatch(connectToServer(`${BASE_URL}user/signIn`, {
email: state.email,
password: state.password
}, 'post'))
if (response.data.token) <--- this data is 1 step late
//do smth
I see relevant data only in JSX elements when they are rendered, but there is no way to make a function based on this data, this data is 1 step late.
There's three issues here:
The connectToServer action is presumably doing some async work, so there's no way a response can have been updated by the time the next line runs
Even if you do await dispatch(connectToServer()), React may not have re-rendered yet
The callback can only reference the variable values that existed in scope at the time the callback was defined, ie, the render before the user clicked the "Submit" button.
You'll need to either:
Move the response handling into the thunk itself
Have the thunk retrieve the updated data from the store and return it / use it somehow
Move the response token handling into a useEffect and wait for the next re-render that has the right data
I just wanted a clarification on this
state = {
foodList: [],
currentFoodItem: null,
}
onFoodsReceived = (foodList) => {
console.log(foodList);
this.setState(prevState => ({
foodList: prevState.foodList = foodList
}));
}
In the above code it uses a prevState to replace a list value when u can use the code below. Why some uses prevstate while others don't to replace a list value
onFoodsReceived = (foodList) => {
console.log(foodList);
this.setState({
foodList: foodList
}));
}
It is used when we want to override the current state with the last state's parameters.
From React docs :
According to the React docs "React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state."
"To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument"
Sources.
I am fetching data from a server, and I would like to do this every time the user enters the screen. The problem is, I start getting the data when the screen function is called, and apparently there isn't enough time to fetch the data before the screen is populated. What I am trying now is something like:
function MyScreen() {
model.refreshData();
const data = model.getData();
return (<View><Text>{data}</Text></View>);
}
This does not work, because, again, data has not been refreshed by the time that we do the "getData". I can't use a .then, because then I won't be able to return the (<View><Text>{data}</Text></View>) part. Is there a way that I can force the screen to update once model.refreshData() has finished?
Use reactive state to change the return value of MyScreen when the data is done loading. The following is pseudocode:
function MyScreen() {
const [screenData, setScreenData] = useState(null);
model.refreshData();
setScreenData(model.getData());
// Component will render nothing until data is finished loading
if (!screenData) {
return null;
}
// Once data is loaded your full component will render
return (<View><Text>{screenData}</Text></View>);
}
If getData() is a promise then instead of
setScreenData(model.getData());
do
model.getData().then((data) => setScreenData(data));
I am new to React Native
I am trying to create a multiselect view where user can select and deselect the items and then the selected items should pass back to the previous container and when user comes back to the next view the selected items should be checked.
I am trying to implement but getting the issue it is not updating data accurately. It shows only 1 selected item when I came back again to the screen.
Can anyone tell me the best way to do that or if there is any tutorial.
Should I do it with Redux or using react native?
Any help would be appreciated!!
Thanks!!
I believe the issue you describe is due to the following:
In componentDidMount you are calling updateItemWithSelected in a loop. This updateItemWithSelected call is both overwriting the checked attributes for all of the arrayHolder values on each call and also not using the updater function version of setState, so the later call of the loop may overwrite the earlier calls since setState is async and batched. If you are not using updateItemWithSelected elsewhere you should simplify componentDidMount to:
componentDidMount() {
const selectedTitles = {};
const { state } = this.props.navigation
const params = state.params || {};
if (params.data.length){
params.data.forEach((element) => {
// create a map of selected titles
selectedTitles[element.title] = true;
})
}
const arrayHolder = this.array.map(item => {
// map over `this.array` and set `checked` if title is in `selectedTitles`
return {...item, checked: !!selectedTitles[item.title]};
});
this.setState({ arrayHolder });
}
and delete updateItemWithSelected.