Figure out if TextInput has focus via ref - react-native

The configuration is as follows:
class MyComponent extends Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
...
render() {
...
<TextInput style={styles.textInput}
...
ref={this.inputRef}
/>
...
}
}
Q. How to find out if TextInput has focus within a render() method?

you can check either by using this functions or by creating your custom setup by registering onBlur() and onFocus() callback functions in your textInput.
e.g.
<TextInput
onFocus={() =>console.log("focus received" ) }
onBlur={() => console.log("focus lost") } />

Related

my Button cannot change a state in another react native component

Why does the following code not work? In this test I simply try to show a state of the component Board, when the Button is clicked. But I get a TypeError: undefined is not an object.
var board = (<Board/>);
return (
<View>
{ board }
<Button
title="Press me"
onPress={() => Alert.alert(board.state.lastRefresh)}
/>
</View>
);
};
The Board component has this constructor:
constructor(props) {
super(props)
this.state = {
lastRefresh: Date(Date.now()).toString(),
}
...
If your Board component is something like this:
import PageTwo from 'PageTwo';
export default class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
lastRefresh: Date(Date.now()).toString(),
}
}
render() {
return (
<View>
<PageTwo lastRefresh={this.state.lastRefresh}>
</PageTwo>
</View>
)
}
}
You can access your props by this way from PageTwo component:
export default class PageTwo extends React.Component {
render() {
return (
<View>
<Button
title="Press me"
onPress={() => Alert.alert(this.props.lastRefresh)}
/>
</View>
)
}
}

how to input get focus every time in react navigation

I use react navigation TabNavigator and I want every time user goes to second tab, one TextInput in screen get focus and keyboard gets popup
You can use refs and react navigation lifecycle for this:
constructor(props) {
super(props);
this.input = React.createRef();
this.didFocusDSubscription = this.props.navigation.addListener(
'didFocus',
payload => {
this.input.current.focus();
}
);
}
render() {
return <TextInput ref={this.input} />;
}
this might help you
this.viewDidAppearListener = this.props.navigation.addListener('didFocus', (payload) => this._viewDidAppear(payload));
didFocus event will be triggered every time the view is showed (like viewDidAppear in iOS) so you can then do focus() on your textinput manually.
Simplest is to add "autoFocus" to your textInput
Like this:
<TextInput
placeholder="Type any activity name"
placeholderTextColor="lightgray"
...
ref="textInput"
autoFocus />
For react-navigation#3.X.X use navigation.addListener and .focus():
class AutoFocusedTextInput extends React.Component {
state = {
text: '',
}
componentDidMount() {
this.props.navigation.addListener('didFocus', payload => {this.textInput.focus()})
}
componentWillUnmount() {
didFocusSubscription.remove();
}
render() {
return (
<View>
<TextInput
ref={(component) => this.textInput = component}
autoFocus={true}
placeholder="Start typing"
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
</View>
)
}
}
The reference:
https://reactnavigation.org/docs/3.x/navigation-prop#addlistener---subscribe-to-updates-to-navigation-lifecycle

Changing state from a child component

So, I've just figured out today that only changing state in a React Native app triggers a re-render of the component. I'm changing state, but I'm doing it from a child component, and it seems to getting stuck in some loop, and () => { this.setState({current_time:'whatever'}) doesn't seem to do anything at all. How can I change my App.js's current_time in state from TimePicker.js?
App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
current_time:'initial time, unchanged in state',
};
}
render() {
let s = styles;
return (
<View style={s.contain}>
<TimePicker />
<ShowTime current_time={this.state.current_time} />
</View>
);
}
}
TimePicker.js
class TimePicker extends Component {
constructor(props){
super(props);
}
render(){
let s = styles;
return(
<TouchableOpacity>
<View style={s.contain} onPress={
/*
set this.state.current_time in parent to the actual current time
this.setState({current_time:'changed'}) seems to cause an infinite loop?
() => { this.setState({current_time:'changed'}) } doesn't seem to do anything
*/
}>
<Text>I will change the time in state.</Text>
</View>
</TouchableOpacity>
)
}
};
ShowTime.js
class ShowTime extends Component {
constructor(props){
super(props);
}
render(){
let s = styles;
return(
<View style={s.contain}>
<Text>{this.props.current_time}</Text>
</View>
)
}
};
Create a function in App.js and pass it as prop to TimePicker Component and the purpose of this function should be to setState . e.g
App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
current_time:'initial time, unchanged in state',
};
}
currentTimeHandler = (newCurrentTime) => {
this.setState({current_time: newCurrentTime});
}
render() {
let s = styles;
return (
<View style={s.contain}>
<TimePicker getTime={ this.currentTimeHandler }/>
<ShowTime current_time={this.state.current_time} />
</View>
);
}
}
TimePicker.js
class TimePicker extends Component {
constructor(props){
super(props);
}
render(){
let s = styles;
return(
<TouchableOpacity onPress={() => this.props.getTime('changes will be passed here')}>
<View style={s.contain} >
<Text>I will change the time in state.</Text>
</View>
</TouchableOpacity>
)
}
};
The reason is the setState only set the existing states locally in the js file. that would be your Timepicker.
In your case TimePicker is a child(or sub branch) of App (Your app stores your state, by your current build, and will never be changed by a child). You will need create two functions one in TimePicker and another App. TimePicker will handle the data and send it, via prop, the App will receive the prop and then trigger another function to setState.
Pass data from child to parent in React
This is the best one i can find.
Best read this as well:
https://reactjs.org/docs/react-component.html
It does say, setState only affect to local states, your state you want to set is not local.

Passing React Native Input Field to State

Background
I am working with a React Native application and I have a login form. The login form input field is passing email to state on button click.
I am trying to console.log the email field. this.state.email but I keep getting email not defined.
I have removed the firebase functions to make it easier to read. But at the top of the form the console.log never succeeds.
Examples
These are the components I am working with.
Input Component
This input component is to be used in LoginForm.
class Input extends Component {
constructor(props) {
super(props);
this.state = {
value: '',
onChangeText: ''
}
}
render() {
return(
<View}>
<Text>{this.props.label}</Text>
<TextInput
value={this.value}
onChangeText={this.onChangeText}
/>
</View>
);
}
}
LoginForm Component
class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
};
}
signIn() {
console.log(this.state.email);
}
render() {
return(
<Card>
<CardSection>
<Input
value={this.state.email}
onChangeText={(email) => this.setState({email})}
/>
</CardSection>
<CardSection>
<Button
onPress={() => this.signIn()}
btnTxt='Sign In'
/>
</CardSection>
</Card>
);
}
Question
What is the proper way to pass the input field "email" to state so I can use it in my Firebase Authentication function?
In the code featured in your question, your Input component is calling this.onChangeText on onChangeText, this isn't referencing the same function you passed down as a prop from LoginForm.
class Input extends Component {
constructor(props) {
super(props);
this.state = {
value: '',
onChangeText: '',
};
}
render() {
return (
<View>
<Text>{this.props.label}</Text>
<TextInput
value={this.value}
onChangeText={email => this.props.onChangeText(email)}
/>
</View>
);
}
}

loading/importing contents of Modal from another js (class) file in react-native

My modal displays an input form. I want to import contents of my Modal from another js file for keeping the main code shorter. I am actually able to import contents of my Modal from another class file by calling component's class name as jsx tag, but in this case I cannot pass state variables of main component to inner component of the modal or vice versa. And, I don't know if it is possible to receive data from the modal in this case. I know that I could use navigator with passProps, but I want to use just a modal for this purpose. For instance:
this is main Component:
class Main extends React.Component {
constructor(props){
super(props);
this._showAddNewModal = this._showAddNewModal.bind(this);
this.state = {
addNewShow: false,
mytext: '' // this should be updated through Modal.
}
}
render(){
return (
<TouchableHighlight onPress={() => {this._showAddNewModal();}}>
<Text> Show my modal </Text>
</TouchableHighlight>
<Modal visible={this.state.addNewShow}>
<MyModalContents />
</Modal>
);
}
_showAddNewModal(){
this.setState({addNewShow: true});
}
}
this is the component to be displayed in the modal:
class MyModalContents extends React.Component { // extends Modal?
constructor(props){
super(props);
this.state = {mytext: ''}
}
render(){
<View>
<TextInput onChangeText={(text) => this.setState({mytext: text})} />
</View>
}
}
I can't even close the modal because the state of 'addNewShow' is not accessible from MyModalContents. Any help will be appreciated.
You can pass props to a child component by cloning it with React.cloneElement. Here's an example of how you could use it with your modal:
class Main extends React.Component {
constructor(props){
super(props);
this.state = {
mytext: '' // this should be updated through Modal.
}
}
_showAddNewModal(){
this.refs.modal.show();
}
render(){
return <View>
<TouchableHighlight onPress={this._showAddNewModal}>
<Text> Show my modal </Text>
</TouchableHighlight>
<Modal parent={this} ref="modal">
<MyModalContents />
</Modal>
</View>
}
}
Modal
class Modal extends React.Component {
constructor(props){
super(props);
this.state = {
visible: false,
}
}
show() {
this.setState({visible: true});
}
close(){
this.setState({visible: false});
}
render(){
return <View style={{opacity: this.state.visible ? 1 : 0}} pointerEvents={this.state.visible ? 'auto' : 'none'}>
{/* can pass props with second argument */}
{React.cloneElement(this.props.children, {
parent: this.props.parent,
modal: this
})}
</View>
}
}
MyModalContents
class MyModalContents extends React.Component {
constructor(props){
super(props);
}
_updateModalState() {
const self = this;
// will update the "Main" component state as props are passed through modal
this.props.parent.setState({myText: 'Updated Text!'}, () => {
self.props.modal.close();
});
}
render(){
return <View>
<TouchableHighlight onPress={this._updateModalState}>
<Text> Update Modal State </Text>
</TouchableHighlight>
</View>
}
}