React Native: Proper way to handle huge forms - react-native

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!

Related

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();

React Native number of views count

I am currently working on a mobile app, being developed using react native and expo, where I need to keep track of number of views on a React Native View Component inside a React Native ScrollView Component. The number of views should be the similar to the youtube number of views. Any leads would be really appreciated.
If you want to store the number of time a specific view was hit (similar to YouTube) you could call a small function at the componentDidMount of that class. If you need to have it stored in the back end, you make your API call (I guess a simple function in the back-end increasing the current viewCounter would do).
If you need to display that number, you either can get it from back-end on the initialization of that view (componentDidMount is always a good option) or you can get it before calling the view (i.e. previous screen) and pass it as a parameter.
What you'r saying leave us with some blind side, but here's what I suggest:
in your export use this:
export default function nameOfThePage() {
const [views, setViews] = useState(0);
Call your database api where you're saving those records:
api.get('views')
.then(response => setViews(response.data.views)
and Setup your view:
<View style={setup your style}>
<Text>{Views}</Text>;
</View>

Prevent multiple calls of onPress

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.

React admin: Confirm message on route switch

I want to prevent users from leaving CreateVacancy component by warning them about unsaved changes.
Dealing with ##router/LOCATION_CHANGE via redux saga is of little help, because action is already dispatched and page switch will happen anyways.
Difficulty with React Admin is that I don't have access to <Route/> component directly. Otherwise I would use Route's onLeave prop to achieve my goal.
I need to somehow track previous location (/vacancy/create) and prevent users from leaving to any other route without confirming.
What would you recommend? Thanks.
I think this can be a great feature request. Can you create one on our repository? In the mean time, as we use react-router, you can probably leverage its Prompt component:
import { Prompt } from 'react-router';
const PostCreate = props => (
<Fragment>
<Prompt message="Are you sure you want to leave?" />
<Create {...props}>
...
</Create>
</Fragment>
)
I haven't tested it but it should work. If you need to customize the dialog further, have a look at this article

How to compute data using elements from different branch of state tree in Redux React Native?

I'm new to React, React Native and Redux so I'm trying to wrap my head around alot of these news concepts for the past few days.
One problem I ran into right now is computing new data in Action Creator, before wrapping it around action object and passing into reducer, that requires a piece of data from other branch within the state tree. How would you normally go about solving this? Changing the structure of the global state tree or map this piece of data to the component requiring it?
Given the state tree:
{
ListView:{
dataSource : a ListView.DataSource type
}
SubmitForm:{
title : 'name of title',
text : 'description'
}
isFetchingData: true/false
}
And supposedly, each branch is handled by a different reducer, and each branch's data is passed into separate component as props.
Here's the scenario (I'm translating the React tutorial to React Native using Redux ):
Submit button is clicked in the SubmitForm
--> dispatch an action to notify store that data is being sent, then async grab and send {title,text} to API server.
Upon success ---> compute the dataSource returned from API server and pass the result dataSource to reducer (according to the tutorial). And by computing dataSource, I mean dataSource.cloneWithRows(....) (explained here), which requires the dataSource from ListView as seen above.
So my thought was the Form component should not have a prop called dataSource, as this is from another branch in the state tree. But without it, I'm not sure how to achieve the desired dataSource. Changing (merging ListView and SubmitForm in this case) the structure of the state tree would also be strange, as to my understanding about Redux pattern. So could someone help me figure this out? Thanks
Thanks guys. I think I found the best solution by using redux-thunk (well I was actually using redux-thunk to handle async action, but didnt read up the api well enough). Basically the thunk is also injected with getState, so basically calling getState() will gain me access to the global state tree and that should solve my problem.
const actionCreator = (args) => {
return (dispatch,getState) => {
// dispatch action to notify store that data is being sent
fetch(url)
.then((response) => response.json())
.then((resData) => {
// dispatch action to notify data received
// compute new data using resData and current dataSource accessed by getState().ListView.dataSource
})
}
}
I have thought this problem before and I think this may be a way.
For example.
You have actionA,reducerA and branchA of store.
You have actionB,reducerB and branchB of store.
Now you want to read branchA and branchB at the same time and change them.
Ok,let us define two actions.
One in actionA(sub-actionA), which to change the branchA.
Another in actionB(sub-actionB), which to change the branchB.
And then, define a total action(total-action),which will call sub-actionA and sub-actionB in order.
The last problem is "How to read branchB in the sub-actionA".
ok, we can use the method 'getState' of store.
We import the store into the actionA, and call
store.getState()
It will return the whole tree of store.
This is a common question, and conveniently has an answer over in the Redux FAQ.
Short version: combineReducers solves a simple use case of splitting reducer functionality by domain/slice-of-state. You've gone past that, and now need to either add custom additional top-level reducer logic to handle this action, or include the additional needed data in the action itself.