How to make e.target.value in React-native? - react-native

I am transferring React to React Native.
But I am sticked to the problem using e.target.value.
This is a code of React that works well.
_searchContact = (e) => { this.state.keyword
this.setState({
keyword : e.target.value
});
}
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
<input
name="keyword"
placeholder="Search"
value={this.state.keyword}
onChange={this._searchContact}
/>
And I tried to write again with the way of React-native
But it doesn't work.
_searchContact = (e) => {
this.setState({
keyword : e.nativeTarget.value
});
}
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
name="keyword"
placeholder="Search"
onChangeText={this._searchContact}
value={this.state.keyword}
/>

If you are using onChangeText you'll have to use an anonymous function and pass in 'text' like so
(text) => this._searchContact(text)
And instead of passing e into your method pass test in as a parameter and set keyword equal to text.
_searchContact = (text) => {
this.setState({
keyword : text
});
}

Just use e as the value and set it to keyword in setState.
Your code should work only with the below code:
_searchContact = (e) => {
this.setState({
keyword : e
});
}
Actually onChange and onChangeText are both fired when text input's text changes, but onChange doesn't provide the changed text, its just a mere intimation callback, so to extract value of the current text being typed, onChangeText gives a callback with the changed text as the param for the callback.
For reference read this.

Related

React native: race condition in TextInput

I encountered an issue with TextInput, which gets input from user, and a button which send the message in TextInput and clear the input.
So overall flow would be:
User type into TextInput
At some point, user presses Button(aka. TouchableOpacity)
Store the text from the TextInput to temporary buffer then clear the TextInput.
Send the text via api.
Code looks like:
{/* Message Input */}
<TextInput
style={styles.messageInput}
multiline
onChangeText={text => {
setMessage(text);
}}
value={message}
/>
{/* Send Button */}
<Button
title={"Send"}
onPress={() => {
const msg = message
onSendMessage(msg);
setMessage("");
}}
disabled={false}
style={styles.sendButton}
/>
And my problem occurs when user type too soon after tapping the send button.
If user decides to type too soon, then TextInput does not get cleared.
I think this is because:
User tap send => enqueues render because message state change by setMessage("") in Button's onPress
User type too soon => enqueues render because message change by onChangeText handler in TextInput. The problem is setMessage from previous state hasn't been really handled yet. Therefore, this render is enqueued with message's previous value (aka. value before message was set to "" ).
I tried Promise, useEffect, and useRef, but nothing really solved this issue. If anyone knows how to overcome with this issue, please let me know. Thank you in advance.
You should use Callback or Promise or Async/Await for this use-case. I suggest you use Promise.
onSendMessage = msg => {
axios
.post("/your-url", {
msg
})
.then(function(response) {
console.log(response);
// ! You can clear the message here !
setMessage("");
// OR
return new Promise(() => resolve(msg));
})
.catch(function(error) {
console.log(error);
});
};
Something like that. The choice of using is yours :)
useState hook is asynchronous, and will not immediately reflect and update but will trigger a re-render. Therefore you shouldn't store this value in a constant like this: const msg = message.
I'd make an async function that sends the input to the api. (Bonus: add an loading state to give the user feedback by disabling the submit button)
const [isLoading, setIsLoading] = useState(false);
onSubmit = async () => {
setIsLoading(true);
const response = await fetch('url/action', settings);
if(response){
setIsLoading(false);
return response.json();
}
}
<TextInput
style={styles.messageInput}
multiline
onChangeText={text => {
setMessage(text);
}}
value={message}
/>
<Button
title={"Send"}
onPress={() => onSubmit()}
disabled={isLoading}
style={styles.sendButton}
/>

How to allow text input in list item using react native?

This question relates to React Native specifically the text input component. I wanted to create an app which allows users to select a number of people from their contacts and based on their selection, create a list with text input each beside them. From there, they are able to do text input and with the onChangeText function, changes the state of a particular key.
Below is the code that I have attempted. I tried to change the state of percent inside the prop which I believe is incorrect since all elements will share the same text input.
By doing so, whenever I made a text input to one field, the text input will erase subsequently.
constructor(props) {
super(props);
this.state = {
selected2: undefined,
description: "",
amount: "",
notes: "",
percent: {},
selectedContacts:
this.props.navigation.state.params.selectedContacts,
};
}
const SelectedList = (props) => {
const list = ({ allContacts }) => {
if (allContacts) {
return allContacts.map((item) => {
return (
<ListItem key={item.id}>
<Body>
<Text>{`${item.first_name}`}</Text>
<Text note>{`${item.phone_number}`}</Text>
</Body>
<Right>
<Item>
<Input
placeholder="0"
maxLength={3}
onChangeText={(percent) => {
this.setState({percent});
}}
/>
<Text>%</Text>
</Item>
</Right>
</ListItem>
)
})
}
}
<SelectedList
allContacts={this.state.selectedContacts}
/>
I hope to achieve is that after selecting the number of contacts and transferring the array data, I want the array to be printed out and the text input of each list item to be independent of each other.
Any feedback and advice are welcome and I really appreciate for you to spending time reading my query and helping me with my problem. Thank you!
I think its about your logic.. something like this should work. make 'percent' type to array and in onChangeText change specific item
this.state = {
...
percent: [],
...
}
...
return allContacts.map((item,index) => {
...
onChangeText={(someText) => {
var {percent} = this.state;
percent[index] = someText;
this.setState({percent});
}}

How do i call a function outside of Field render method in React-native?

Hi Experts i'm a newbie in react-native, help will appreciated.
I need to call a method name openModel() which is globally declared in Component and i have a method renderInput which renders each Input passed in Field tag. When openModel() is call inside renderInput of its Inputs on Focus. Error shows _this4.openModel is not a function. Its clearly understood that this is getting incremented because of multiple time renderInput method is called.
How do i fix this ?
Below is short code
class AddPatientForm extends Component {
constructor(props) {
super(props);
openModel = () => {
this.refs.bGroup.open();
}
renderInput({ input, label, type, meta: { touched, error, warning } }) {
return (
<View style={{ flexDirection: "row", height: 25, paddingRight: 5, }}>
<Input
ref={c => { this.textInput = c }}
returnKeyType={input.name === "Password" ? "" : "next"}
onSubmitEditing={() => { this.textInput._root.focus(); }}
blurOnSubmit={false}
secureTextEntry={input.name === "Password"}
{...input}
onFocus={() => this.openModel()}
keyboardType={input.name === "mobile" || input.name === "age" ? "numeric" : "default"}
autoCapitalize="none"
/>
</View>
);
}
<Field name="patientId" component={this.renderInput} type="" validate={[alphaNumeric,required]} />
}
you can simply write OpenModel() like this -
openModel() {
this.refs.bGroup.open();
}
Hope it works !
Please remove your openModel() function from constructor it will work for you if you define your function outside of constructor
openModel = () => {
this.refs.modal2.open();
}
you can call your function and define inside of class then directly using this.openModel();
if you have globally function and define outside of class then you don't need to use this keywords.

How to use event.value in React-Native

The event doesn't work in React-Native.
This is textInput.
<TextInput
id="name"
placeholder="name"
onChange = {this._inputChange}
/>
And This is the onChage function.
when i check with console.log(e.nativeEvent.id) writing in TextInput, it says undefined.
I guess that e.target.id can't use in React-native not React.
Could you recommend some idea?
_inputChange = (e) => {
let nextState = {};
console.log(e.nativeEvent.id)
nextState[e.nativeEvent.id] = e.nativeEvent.value;
this.setState(nextState);
}
This is how I handle this...
handleChange = (field, value) ={
this.setState({ [field]: value });
}
<TextInput
onChangeText={this.handleChange.bind(this, 'name')}
...
/>

Update Input Value while mapping React Native

I am creating react-native mobile app. I have an array with some values. I want to set array's value into input field. I have added value in the fields but i can't able to update these values. I have set my values in a qty variable like this:
constructor(props) {
super(props);
this.state = {
qty:[],
}
}
componentWillMount() {
var ids = [];
this.props.data.map((dataImage,Index) => {
dataImage['pro-name'] != undefined && (
ids.push({'qty':dataImage['pro-qty']})
)
})
this.setState({qty:ids})
}
render() {
return {
this.props.data.map((dataImage,Index)=>(
<View key={Index} style={productStyle.cartview}>
{dataImage['pro-name'] && (
<View style={productStyle.cartmain}>
<Input value={this.state.qty[Index]['qty']} onChange={this.handleChangeInput.bind(this)} style={{width:40,height:40,textAlign:'left'}} />
</View>
)}
</View>
))
}
}
Its showing values properly into the input field but i can't able to type anything into the field to update the values. what can i do for this
I will suggest you to move your input container into separate class, its better approach and each component will handle its own state. Its easy to handle and will result better in performance too.
components = []
render() {
return this.props.data.map((item, index) => (
<CustomComponent data={item} index={index} ref={(ref) => this.components[index] = ref} />
))
}
You can then get child (CustomComponent) value from its ref.
this.components[index].getValue()
this.components[index].setValue('Value');
You will need to create these functions (getValue & setValue) in CustomComponent class.
solution
Here is solution to your query. You need to install lodash or find other solution to make a new copy qty.
<Input onChangeText={(text) => this.handleChangeText(text, index)} />
handleChangeText = (text, index) => {
const qty = _.cloneDeep(this.state.qty);
qty[index] = {
qty: text
}
this.setState({qty})
}
Your Input's value is set to this.state.qty[Index]['qty']. And to change it on text edit, you can do it like this. You do not need to bind the function, instead use an arrow function like this.
onChangeText={ (newValue) => {
this.setState({ <your-input-value-state>:newValue })
}}
You have to update the value of each Input individually on onChange event.
Replace your with Input with this
<Input value={this.state.qty[Index]['qty']}
onChange={this.handleChangeInput.bind(this, Index)}
style={{width:40,height:40,textAlign:'left'}}
/>
and update the state accordingly with the Index when the event is called
handleChangeInput(index, value){
let {qty} = this.state;
let qty_update = qty.slice();
qty_update[index]['qty'] = value;
this.setState({qty: qty_update});
}