In React Native 16.
Get input value
<Input
...
onChange={event => getValue(event)}
/>
Output value
const getValue = event => {
console.log(event.nativeEvent.text);
};
The Input component from react-native-elements is basically rendering the TextInput component. So you can use onChangeText instead of onChange like
import React, { Component } from 'react';
import { Input } from 'react-native-elements';
export default function UselessTextInput() {
const [value, onChangeText] = React.useState('Useless Placeholder');
return (
<Input
onChangeText={text => onChangeText(text)}
value={value}
/>
);
}
Hope this helps
Set value to the state.
const getValue = event => {
this. setState({text: event.nativeEvent.text});
};
Related
I need your help. Now I'm trying to create a todo application.I will try to make an application on the logic of pure react.The problem is that when I start typing input, I get an error: undefined is not an object (evaluating 'e.target.value).Please help me with this task. I will be very grateful to you
Tasks.js
import React, {useState} from "react";
import {FlatList, StyleSheet, Text, View} from "react-native";
import Task_Item from "./Task_Item";
import Form from "./Form";
export default function Tasks() {
const [tasks, setTasks] = useState([]);
const [input, setInput] = useState('');
let addTask = (myInput) => {
if (myInput) {
let newTask = {
id: Date.now(),
name: myInput
}
setTasks([...tasks, newTask])
}
}
let handleInput = (e) => {
setTasks(e.target.value)
}
return (<View style={styles.all_list}>
<FlatList data={tasks}
renderItem={({item}) => (<Task_Item keyExtractor={item => item.id} el={item}/>)}
/>
<Form addTask={addTask} inputValue={handleInput}/>
</View>)
}
Task_item.js
import React from "react";
import {StyleSheet, TouchableHighlight, Text, ScrollView} from "react-native";
export default function Task_Item({el}) {
return (<ScrollView>
<TouchableHighlight>
<Text>{el.name}</Text>
</TouchableHighlight>
</ScrollView>)
}
Form.js
import React from "react";
import {KeyboardAvoidingView, StyleSheet, Text, TextInput} from "react-native";
export default function Form({inputValue, addTask}) {
return (<KeyboardAvoidingView>
<TextInput
placeholder='Type Text...'
onChangeText={inputValue}
/>
<Text
onPress={addTask}
>+</Text>
</KeyboardAvoidingView>)
}
I see two things you could improve.
The onChangeText method directly passes you the text, so you should either pass the setInput to your inputValue Form prop, either change the onChangeText to the onChange.
Using onChangeText
Tasks
<Form addTask={addTask} inputValue={setInput} />
Form.js
<TextInput placeholder="..." onChangeText={inputValue} />
And therefore you can delete the handleInput method.
with onChange
Tasks
<Form addTask={addTask} inputValue={handleInput} />
Form.js
<TextInput placeholder="..." onChange={handleInput} />
The second thing is that you handleInput method is changing your tasks and not your input...
const handleInput = (e) => setInput(e.target.value)
Your addTask is not getting the input... You could change your method to this:
const addTask = () => {
if (input) setTasks([...tasks, { id: Date.now(), name: input }])
}
I am developing react-native project.
I have created a custom component inside which I use a 3rd party library component. The 3rd party library component needs the useRef hook from my code so that I can control the library component.
import React, {useRef} from 'react';
...
const MyComponent = () => {
const ref = useRef();
return (
<View>
<Button
title="OPEN 3rd party component"
onPress={() => ref.current.open()}
/>
<LibraryComponent
ref={ref}
...
/>
</View>)
}
Now, I have a screen named MyScreen, I need to show MyComponent on MyScreen, and control that library component from MyScreen instead of MyComponent. So, I refactored MyComponent to this (I removed the Button and change ref to be a pass-in property):
const MyComponent = ({ref}) => {
return (
<View>
<LibraryComponent
ref={ref}
...
/>
</View>)
}
Then, in MyScreen :
import React, {useRef} from 'react';
import MyComponent from '../components/MyComponent';
export const MyScreen = () => {
const screenRef = useRef();
...
return (
<View style={styles.container}>
<Button onPress=>{()=>screenRef.current.open()}/>
<MyComponent ref={screenRef}>
...
</View>
)
}
But I get warning message: Function components cannot be give refs. Attempts to access this ref will fail. Did you mean to use React.ForwardRef() ?
My questions is:
How to get rid of that warning & having MyScreen control the library component with reference hook?
======== UPDATE =======
I changed the name of the property in MyComponent from ref to innerRef like #Rishabh Anand suggested. The warning disappeared.
const MyComponent = ({innerRef}) => {
...
}
MyScreen is now:
export const MyScreen = () => {
const screenRef = useRef();
...
return (
<View style={styles.container}>
<Button onPress=>{()=>screenRef.current.open()}/>
<MyComponent innerRef={screenRef}>
...
</View>
)
}
But now a new issue comes, when I click on the Button of MyScreen, app crashed with error undefined is not an object (evaluating screenRef.current.open). It seems the screenRef.current holds a null instead of the library component. Why?
You have to use React.forwardRef
From the docs: https://fr.reactjs.org/docs/forwarding-refs.html
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
const ref = React.createRef();
<FancyButton ref={ref}>Cliquez ici</FancyButton>;
You can after you set a ref, call some function inside your child component like this:
const FancyButton = React.forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
click: () => {
onClick();
},
}));
const onClick = () => {
console.log('Clicked.');
};
return (
<button onClick={onClick} className="FancyButton">
{props.children}
</button>
);
});
const ref = React.createRef();
<FancyButton ref={ref}>Cliquez ici</FancyButton>;
And call from your parent component
ref.current.click()
I'm creating my own searchbar in react-native, so I want to allow user clear the text input. To achieve this I'm using useState to track when the text input value is empty or not. I'm executing onStateChange('') to clean the text input value, the problem is if I access to value this show the value before onStateChange('') not empty string ''.
e.g. If I type react on input and after that execute onStateChange('') I expect the input value property to be empty, but it is not, value contains react yet, If I press other key the value is '' and not the current one. i.e. it is not saving the last value entered but the previus one.
SearchBar Usage
import React, { useState } from 'react';
import {
TextInput,
TouchableWithoutFeedback,
View,
} from 'react-native';
function SearchBar(props) {
const {
onChangeText,
value = '',
...textInputProps
} = props;
// Access to native input
const textInputRef = React.createRef();
// Track if text input is empty according `value` prop
const [isEmpty, setIsEmpty] = useState(value ? value === '' : true);
const clear = () => {
// Clear the input value with native text input ref
textInputRef.current?.clear();
// Update the text input `value` property to `''` i.e. set to empty,
if (onChangeText) onChangeText('');
// this is where the problem lies, because If I check the input text `value` property, this show the previus one, not the current one.
console.log(value);
};
const handleOnChangeText = (text) => {
if (onChangeText) onChangeText(text);
// track if text input `value` property is empty
setIsEmpty(text === '');
};
// Render close icon and listen `onPress` event to clear the text input
const renderCloseIcon = (iconProps) => (
<TouchableWithoutFeedback onPress={clear}>
<View>
<Icon {...iconProps} name="close" pack="material" />
</View>
</TouchableWithoutFeedback>
);
return (
<TouchableWithoutFeedback onPress={focus}>
<View>
<TextInput
{...textInputProps}
onFocus={handleOnFocus}
onBlur={handleOnBlur}
onChangeText={handleOnChangeText}
ref={textInputRef}
/>
// helper function to render a component with props pased to it
<FalsyFC
style={{ paddingHorizontal: 8 }}
// If text input `value` is `isEmpty` show the `x` icon
component={!isEmpty ? renderCloseIcon : undefined}
/>
</View>
</TouchableWithoutFeedback>
);
}
SearchBar Usage
function SomeComponent() {
const [search, setSearch] = useState('');
const updateSearch = (query: string) => {
setSearch(query);
};
return (
<SearchBar
onChangeText={updateSearch}
value={search}
/>
)
}
I think you are missing a value prop in the TextInput (see React Native doc for TextInput).
In your case you would set your value variable from the props object you pass to the SearchBar functional component:
<TextInput
{...textInputProps}
onFocus={handleOnFocus}
onBlur={handleOnBlur}
onChangeText={handleOnChangeText}
ref={textInputRef}
// add the line below
value={value}
/>
Every state changes are asynchronous even Hooks. With useState() you can't define a callback function even onStateChange() is not called. In your case, you should use the function useEffect().
function SomeComponent() {
const [search, setSearch] = useState('');
useEffect(() => {
//Write your callback code here
//copy-paste what you wrote on function onStateChange()
}, [search]);
const updateSearch = (query: string) => {
setSearch(query);
};
return (
<SearchBar
onChangeText={updateSearch}
value={search}
/>
)
}
Here is a link that should help you :
https://dmitripavlutin.com/react-useeffect-explanation/#:~:text=callback%20is%20the%20callback%20function,dependencies%20have%20changed%20between%20renderings.
I followed the chosen answer in this thread, but I couldn't figure it out. I want to test the value of a TextInput component so I could check the length of it, what is the proper way to achieve this today?
My component looks something like this:
import React, {useState, useEffect} from 'react';
import {TextInput} from 'react-native';
export default function TextInputComponent(props) {
const [text, setText] = useState('');
useEffect(() => {
props.text ? setText(props.text) : setText('');
}, []);
const handleInputTextChange = text => {
setText(text);
};
return (
<TextInput
onChangeText={text => handleInputTextChange(text)}
value={text}
maxLength={maxLength}
testID="text-input"
/>
);
}
And the test file I constructed so far:
import React from 'react';
import renderer from 'react-test-renderer';
import {render} from 'react-native-testing-library';
import TextInputComponent from 'components/textInputComponent/textInputComponent';
describe('<TextInputComponent />', () => {
it('renders correctly', () => {
renderer.create(<TextInputComponent />);
});
it('should show "AAA" with text="AAAA" and maxLength="3" props', () => {
const props = {
text: 'AAAA',
maxLength: 3,
};
const {queryByTestId} = render(<TextInputComponent {...props} />);
const textInput = queryByTestId('text-input');
console.log(textInput);
});
});
I think what you're trying to do is to limit the initial text passed in props to the maxLength of characters passed.
in your component useEffect() ,
instead of:
props.text ? setText(props.text) : setText('');
slice the initial text:
props.text ? setText(props.text.slice(0, maxLength)) : setText('');
that should work for having the text length less than the maxLength too.
I'm using DatePicker with ReduxForm. However, when I click submit button, the input value from Date Picker not pass to Redux Form.
I've search around and come across the answer from this (my code of renderDatePicker comes from there) but it still doesn't work for me.
My demo of the form on my Simulator:
Here's my code:
import React, { Component } from 'react';
import {
View, Text, Button, Icon, Container, Item,
Input, Label, Content, Form, Picker, Footer, DatePicker
} from 'native-base';
import { Field, reduxForm } from 'redux-form';
import { addTransactionItem } from '../redux/ActionCreators';
import moment from 'moment';
import { connect } from 'react-redux';
const mapDispatchToProps = dispatch => ({
addTransactionItem: (transactionItem) => dispatch(addTransactionItem(transactionItem))
})
class AddTransaction extends Component {
constructor(props) {
super(props);
this.renderField = this.renderField.bind(this);
this.submit = this.submit.bind(this);
this.renderDatePicker = this.renderDatePicker.bind(this);
}
renderDatePicker = ({ input, placeholder, defaultValue, meta: { touched, error }, label ,...custom }) => (
<Item>
<Label>{label}</Label>
<DatePicker {...input} {...custom} dateForm="MM/DD/YYYY"
onChange={(value) => input.onChange(value)}
autoOk={true}
selected={input.value ? moment(input.value) : null} />
{touched && error && <span>{error}</span>}
</Item>
);
submit = values => {
alert(`The values are ${JSON.stringify(values)}`)
const transactionItem = JSON.parse(JSON.stringify(values))
this.props.addTransactionItem(transactionItem);
const { navigate } = this.props.navigation;
navigate('Home');
}
render() {
const { handleSubmit } = this.props
return (
<>
<Form>
<Field keyboardType='default' label='Date' component={this.renderDatePicker} name="date" />
</Form>
<Button full light onPress={handleSubmit(this.submit)}>
<Text>Submit</Text>
</Button>
</>
);
}
}
AddTransaction = connect(null, mapDispatchToProps)(AddTransaction);
export default reduxForm({
form: 'addTransaction',
})(AddTransaction);
I think this is because you do not have "change" attribute in the Field component.
Try to add change function as shown below:
renderDatePicker = (
{
input,
placeholder,
defaultValue,
meta: { touched, error },
label ,
...custom,
change
}
) => (
<Item>
<Label>{label}</Label>
<DatePicker {...input} {...custom} dateForm="MM/DD/YYYY"
onDateChange={change}
autoOk={true}
selected={input.value ? moment(input.value) : null} />
{touched && error && <span>{error}</span>}
</Item>
);
render() {
const { handleSubmit, change } = this.props
return (
<>
<Form>
<Field
keyboardType='default'
label='Date'
component={this.renderDatePicker}
name="date"
change={change}
/>
</Form>
<Button full light onPress={handleSubmit(this.submit)}>
<Text>Submit</Text>
</Button>
</>
);
}
Hope it will work for you.
I see that there is no onChange listener for DatePicker. May be you should use onDateChange. http://docs.nativebase.io/Components.html#picker-input-headref