Prevent multiple calls of onPress - react-native

I have a bottom that adds an item through redux action.
onPress={() => {
this.props.navigation.navigate('Home')
store.dispatch(add(construct(name)))
}}
Sometimes onPress is being called more than once on a single tap and it adds more than one item. I want to prevent that.
Of course I can make a boolean and check if it's true, but it's not very elegant way. Is there a better way to prevent it?

The simple way as you said is to define a boolean flag, but another way to solve your problem is by using redux-saga. I know redux-saga is designed to solve async actions but it can help you here too.
check the takeLatest from here. by this helper, if you click more than one time, it will run the latest one only.

Related

React Native: Proper way to handle huge forms

I have an application developed for internal users. The home page of the app has at least 30 input fields.
<TextInput onChangeText={onChangeNumber} value={number}/>
I have onchangeText for all the 30 inputs, in the future I might add more fields. I don't think adding onchange to all the fields is the best way to do it. How can I optimize the approach? Are there any 3rd party packages where it doesn't re-render for every input change and only captures data on submit?
the way I handle large forms is this,
Store your form data in an object using useState like this,
const [formData, setFormData] = useState({name: "", age:""})
you can pass "onChangeText" like this,
<TextInput
value={formData.name}
onChangeText={value => setFormData(prev => { return { ...prev, name: value } })}
/>
I would suggest creating a separate component for "TextInput", so you can also handle validations in it.
Try using onEndEditing, as per docs:
onEndEditing
Callback that is called when text input ends.
So just changing to
<TextInput onEndEditing={onChangeNumber} value={number}/> should do
There are a few other alternatives on the docs, you might check to see the one that fits you better.
https://reactnative.dev/docs/textinput#onendediting
You should try formik + yup.
I am using it in several projects and this is the best way to manage little and big forms!

How to run a callback when vue router-link finished navigation

What I want to do is - the user clicks the router-link - this does not actually do a navigation but just refreshes the page with new data. This is no good for accessibility because the user does not know a navigation happened, but good for performance because full navigation not required.
So I would like some way to solve that problem.
The way I might naively expect to solve the problem is wait for navigation to be over and run a callback, or use a promise and when promise completes run code. The code running when navigation over would put the focus on some element at navigation finished.
I was hoping I could do something obvious like the following
<router-link :to="(router) => {
router.push('/').onComplete(() => {
code to set focus here
});
}"
but it doesn't look like that is possible.
How should I solve my problem, as close to this solution as possible please.
This sounds like you might be using the wrong tools for the job. If you aren't actually navigating, there's no good reason to use router link - if you purely want to have the aesthetics of a link, use <a>. And if you are just expecting data to be refreshed, don't use router.push but simply call the function you want by attaching a listener to the link. If you want to show some kind of loading animation during the data fetching, you could either just set a variable, or use a library like vue-wait
In your case this could be something like:
<a #click="onClick">Link to click</a>
...
data(){
return {
isLoading:false
}
}
methods:{
async onClick(){
this.isLoading=true
await fetch(...)
this.isLoading=false
}
}
To answer your original question as well - yes, it's possible to run code when a navigation is finished. There's quite a few ways to do it, but if you want to specifically run code after a router.push, you can do that - router.push is a promise. So router.push(...).then(...).catch() works as well

How to submit / save form from within the Edit form

I would like to submit the <Edit> form from within the form itself, in order to instantly save the form state upon a simple change e.g. a boolean toggle.
I spent hours trying to find a simple way, and it doesnt seem to exist. The handleSubmit[...] function is only passed to the actions toolbar, and not to the input themselves.
In addition, there seems to be no context hook I can invoke that would provide me access to that function.
One solution I can think of is create a hidden <SaveButton /> inside the actions props, with a ref. Then from the input, I can trigger the <SaveButton /> from the Input. However this seems super hacky, and I would love to find a more straightforward solution.
Is there a theoretical reason why inputs cannot access the submit function?
You can use the useSaveContext hook which is not yet documented:
import { useSaveContext } from 'react-admin';
const { save, saving } = useSaveContext();

After inserting new data how to reload the page in react-native and i'm using mobx for state management

I'm using code like this it is not working for me
componentWillRecieveProps(nextProps,nextState){
if(nextProps.navigation.state != this.state){
//here calling api
}
}
I think the question should be more elaborative to help to solve your issue. Based on your questions, you may be asking for either -
How to reload page if data changes
How to reload page if navigation state changes
How to reload page if data changes
In this case, you no need to add 'componentWillRecieveProps'. You can simply check for a value in render method like this
{data.items.length && <ItemLIstCustomComponent />}
or
{data.items.length ? <ItemLIstCustomComponent /> : <EmptyMessageComponent />}
You can look into conditional rendering in react-native.
If the re-render is not happening still? Then your way of updating state/data is not correct. Make sure you make copy of object and update the existing one.
To understand this, read about mutable objects and react shallow-check for re-rendering. Or may be this will help
How to reload page if navigation state changes
I don't think it is good practice to call another API or do any state change related thing in componentWillRecieveProps. You can create a new Screen on which you navigate and call API in componentDidMount.
You can try React navigation if you are not using any navigation library.

Load options on the first open of the Async drop down menu

When I provide loadOptions to an Async control it loads options on mount.
If I pass autoload={false} then it doesn't load options neither on mount nor on open. But it loads options on the first close (or type, or blur).
If I pass onCloseResetsInput={false} then it doesn't load options until I type something. (showing "Type to search" in the menu)
Async provides onOpen handler, but I didn't find the way to use it in this situation. (and react-select#2.0.0-alpha.2 doesn't have it)
So the user needs to type a character, then delete it, to see the full list of options.
How can this be avoided?
Example sandbox: https://codesandbox.io/s/mjkmowr91j
Solution demo: https://codesandbox.io/s/o51yw14l59
I used the Async options loaded externally section from the react-select repo.
We start by loading the options on the Select's onFocus and also set the state to isLoading: true. When we receive the options we save them in the state and render them in the options.
I also keep track of optionsLoaded so that only on the first focus do we trigger the call to get options.
In our use case, we have several of these select inputs on a single page, all async, so the requests to the server will pile up, and are completely unnecessary in a lot of cases (users won't even bother clicking).
I found a workaround for this issue that'll work for my use case on 2.0.0-beta.6:
Include defaultOptions
Add 2 members to your class that will store the resolve/reject methods for the promise.
In your loadOptions function, check if the input is '', if so, create a new promise, and store the values of resolve/reject within your class members, and return that promise. Otherwise, just return the promise normally to get your results.
Add an onFocus handler, and within it call the function to get your results, but also add .then and .catch callbacks passing the resolve and reject functions you stored previously.
Essentially, this makes react-select think you're working on getting the results with a long-running promise, but you don't actually even try to load the values until the field is selected.
I'm not 100% positive there aren't any negative side effects as I just wrote this, but it seems like a good place to start.
Hope this helps someone. I may submit a feature request for this.
In order to load options when user focus first time, set defaultOptions={true}
Thanks, Alexei Darmin for the solution, I was struggling with this... while testing it I converted the solution to a react functional component and added real API fetching.
Here is a working demo, I hope it helps someone