Arguments in React Native Methods - javascript

This is a sample code i am trying to understand.
class Form extends React.Component {
constructor (props) {
super(props)
this.state = {
input: ''
}
}
handleChangeInput = (text) => {
this.setState({ input: text })
}
render () {
const { input } = this.state
return (
<View>
<TextInput style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={this.handleChangeInput}
value={input}
/>
</View>
)
}
}
In this the code that is troubling me is
onChangeText={this.handleChangeInput}
In this piece of code, there is no argument passed to the method(handleChangeInput) which expects text.
Can someone please throw a light here.

Basically you're passing a reference to a function that has the same signature.
React function reference may help shed some light.
given
callback = param => { /* do stuff */ };
then
componentFn={callback};
is equivalent to
componentFn = param => { /* do stuff */ };
but
componentFn={param => callback(param)}
is equivalent to
component = param => { callback(param) } // call function that does stuff
direct reference just removes a middle function binding.

Need to pass the text input to the handleChangeInput
<View>
<TextInput style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) =>{this.handleChangeInput(text)}} value={input}/>
</View>
or set directly the change text value
<TextInput style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({input:text})} value={input}/>

Related

React Native how do I make a Search Bar for a Flatlist?

I have been trying to create a search bar all day. I finally found this guide which seemed ok: https://blog.jscrambler.com/add-a-search-bar-using-hooks-and-flatlist-in-react-native/. I followed it through using my own API and I am not getting any errors exactly, but the code in this tutorial seems unfinished.
Here is what I have:
import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, SafeAreaView, TextInput } from 'react-native';
import { Card, Header } from 'react-native-elements'
import { styles } from './styles.js';
import filter from 'lodash.filter';
const FormsScreen = ({navigation, route}) => {
const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState([]);
const [query, setQuery] = useState('');
const [fullData, setFullData] = useState([]);
//Fetch all users from database
useEffect(() =>{
setIsLoading(true);
fetch('http://10.0.2.2:5000/forms').then(response =>{
if(response.ok){
return response.json();
}
}).then(data => setFullData(data)).then(setIsLoading(false));
}, []);
function renderHeader() {
return (
<View
style={{
backgroundColor: '#fff',
padding: 10,
marginVertical: 10,
borderRadius: 20
}}
>
<TextInput
autoCapitalize="none"
autoCorrect={false}
clearButtonMode="always"
value={query}
onChangeText={queryText => handleSearch(queryText)}
placeholder="Search"
style={{ backgroundColor: '#fff', paddingHorizontal: 20 }}
/>
</View>
);
}
const handleSearch = text => {
const formattedQuery = text.toLowerCase();
const filteredData = filter(fullData, form => {
return contains(form, formattedQuery);
});
setData(filteredData);
setQuery(text);
};
const contains = ({ ID }, query) => {
console.log("ID was: "+ID);
console.log("Query was: "+query);
const id = ID;
console.log('id was: '+id);
if (id.toString().includes(query)) {
return true;
}
return false;
};
if (isLoading) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" color="#5500dc" />
</View>
);
}
else{
return (
<SafeAreaView>
<Header
leftComponent={{ icon: 'menu', color: '#fff' }}
centerComponent={{ text: 'Request Forms', style: { color: '#fff', fontSize: 25} }}
rightComponent={{ icon: 'home', color: '#fff' }}
/>
<FlatList
ListHeaderComponent={renderHeader}
keyExtractor={(item) => item.ID.toString() }
data={fullData}
renderItem={({item}) => (
<Card>
<Card.Title>{item.ID}</Card.Title>
<Card.Divider/>
<View style={styles.Container}>
<Text>{item.Comments}</Text>
{/* <Image source={require('./System apps/Media Manager/Gallery/AppPhotos/45e5cefd-7798-4fe9-88de-86a0a15b7b9f.jpg')} /> */}
<Text>{item.RoadName}</Text>
</View>
<View style={styles.ListContainer}>
<Text style={styles.LabelText}>Name</Text>
<Text style={styles.LabelText}>Phone</Text>
<Text style={styles.LabelText}>Email</Text>
</View>
<View style={styles.ListContainer}>
<Text style={styles.CardText}>{item.Name}</Text>
<Text style={styles.CardText}>{item.Phone}</Text>
<Text style={styles.CardText}>{item.Email}</Text>
</View>
</Card>
)}
/>
</SafeAreaView>
);
}
}
export default FormsScreen;
I have 2 main problems here.
1.) The tutorial had me initialize data and setData. setData is called and it looks to me like that is the final result after the search. The problem is that the author never actually used the variable data so I what do I do with it? Right now the the list is unaltered no matter what happens.
2.) I know he is using a different API so instead of filtering through First name, Last name, and Email I am only searching through ID. In this section of the tutorial:
const contains = ({ name, email }, query) => {
const { first, last } = name;
if (first.includes(query) || last.includes(query) || email.includes(query)) {
return true;
}
return false;
};
How does this code relate first and last to the first and last name values in the data? When I use this code but substitute name with ID and therefor first with id the value of query is correct (19 for example) but the value of ID is 2040 which is not the value I am looking for, but 2040 is the last ID in the database, or in other words the most recently entered row.
This is a sample of my data for reference:
Any help is greatly appreciated.
Please update
data={fullData}
to
data={query ? data : fullData} in flat list props. That should display your filtered data whenever search query updated.

How to make a call back function to populate value prop of textinput onChangeText

In this code all I'm trying to achieve is that I get the typed value inside the value prop of Textinput. However, what I get is null. A setState is asynchronous, I'm lagging one step behind. I am new in react, and I do not know how I can make a callback function that can give me the current value.
I also wish to later use map, and make dynamic form, I appreciate solution that might work for map function as well.
thanks
import React from 'react';
import {
View,
TextInput,
} from 'react-native';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
Email: null,
Password: null,
Address: null,
};
}
EnterValue = (name) => {
return (text) => {
this.setState({
[name]: text,
});
};
};
render() {
return (
<View>
<TextInput
placeholder="enter email"
value={this.state.Email}
onChangeText={this.EnterValue('Email')}
style={{ borderWidth: 2, borderColor: 'skyblue', margin: 20 }}
/>
<TextInput
placeholder="Password"
value={this.state.Password}
onChangeText={this.EnterValue('Password')}
style={{ borderWidth: 2, borderColor: 'skyblue', margin: 20 }}
/>
<TextInput
placeholder="Address"
value={this.state.Address}
onChangeText={this.EnterValue('Address')}
style={{ borderWidth: 2, borderColor: 'skyblue', margin: 20 }}
/>
</View>
);
}
}
I would do something like this
onChangeText={(e) => this.EnterValue(e.target.value, 'Email')}
( I'm not confident with e.target.value, if it's null or undefined, pass e.target and log it, to see what values you can get from it)
then change your function with the following
EnterValue = (value, inputName) => this.setState({ [inputName]: value});

Get the value from TextIput

I want to be able to retrieve the value of the text after the user presses enter/return.
I tried the following ...
class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
text:''
}
}
callTextSubmit = (val) => {
console.log('callTextSubmit ', val);
};
render() {
return (
<View>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({ text })}
onSubmitEditing={(text) => this.callTextSubmit(text)}
value={this.state.text}
/>
</View>
)
}
}
This returns the following... from the console log.
Proxy {dispatchConfig: {…}, _targetInst: FiberNode, isDefaultPrevented: ƒ, isPropagationStopped: ƒ, _dispatchListeners: ƒ, …}
>[[Handler]]:Object
>[[Target]]:Class
>[[IsRevoked]]:false
I want to access the value from the text input, is there a workaround to this? Thank you
The argument for the onSubmitEditing handler is the event, not the current input.
Since you set the state variable text each time the TextInput is changed, you can just use the text variable in your state instead.
callTextSubmit = () => {
console.log('callTextSubmit ', this.state.text);
};
Since you are using this line to add the TextInput's value to state
onChangeText={(text) => this.setState({ text })}
The reasonable way would be to get the value from state on your onPress function on a Button (TouchableOpacity/TouchableHighlight) added to your View like this:
<TouchableOpacity onPress={()=>console.log(this.state.text)}>
<Text>
Enter
</Text>
</TouchableOpacity>
Here is code for your Component
class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
text:''
}
}
callTextSubmit = () => {
console.log(console.log(this.state.text));
};
render() {
return (
<View>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({ text })}
value={this.state.text}
/>
<TouchableOpacity onPress={()=>console.log(this.state.text)}>
<Text>
Enter
</Text>
</TouchableOpacity>
</View>
)
}

How to autofocus next TextInput on react-native

I'm trying to create a passcode protected screen. The screen will uses 4 numeric input as the passcode.
The way I'm doing this is create a TextInput Component and call it 4 times in my main screen.
The problem I'm having is the TextInputs will not focus on the next one as I type the value of the previous TextInput.
I'm using refs for all PasscodeTextInput component (I've been informed that it is a legacy method but I do not know any other way, alas).
Tried this method(without creating my own component), no luck too.
METHOD
index.ios.js
import React, { Component } from 'react';
import { AppRegistry, TextInput, View, Text } from 'react-native';
import { PasscodeTextInput } from './common';
export default class ProgressBar extends Component {
render() {
const { centerEverything, container, passcodeContainer, textInputStyle} = styles;
return (
<View style={[centerEverything, container]}>
<View style={[passcodeContainer]}>
<PasscodeTextInput
autoFocus={true}
ref="passcode1"
onSubmitEditing={(event) => { this.refs.passcode2.focus() }} />
<PasscodeTextInput
ref="passcode2"
onSubmitEditing={(event) => { this.refs.passcode3.focus() }} />
<PasscodeTextInput
ref="passcode3"
onSubmitEditing={(event) => { this.refs.passcode4.focus() }}/>
<PasscodeTextInput
ref="passcode4" />
</View>
</View>
);
}
}
const styles = {
centerEverything: {
justifyContent: 'center',
alignItems: 'center',
},
container: {
flex: 1,
backgroundColor: '#E7DDD3',
},
passcodeContainer: {
flexDirection: 'row',
},
}
AppRegistry.registerComponent('ProgressBar', () => ProgressBar);
PasscodeTextInput.js
import React from 'react';
import {
View,
Text,
TextInput,
Dimensions
} from 'react-native';
const deviceWidth = require('Dimensions').get('window').width;
const deviceHeight = require('Dimensions').get('window').height;
const PasscodeTextInput = ({ ref, autoFocus, onSubmitEditing, onChangeText, value}) => {
const { inputStyle, underlineStyle } = styles;
return(
<View>
<TextInput
ref={ref}
autoFocus={autoFocus}
onSubmitEditing={onSubmitEditing}
style={[inputStyle]}
maxLength={1}
keyboardType="numeric"
placeholderTextColor="#212121"
secureTextEntry={true}
onChangeText={onChangeText}
value={value}
/>
<View style={underlineStyle} />
</View>
);
}
const styles = {
inputStyle: {
height: 80,
width: 60,
fontSize: 50,
color: '#212121',
fontSize: 40,
padding: 18,
margin: 10,
marginBottom: 0
},
underlineStyle: {
width: 60,
height: 4,
backgroundColor: '#202020',
marginLeft: 10
}
}
export { PasscodeTextInput };
Update 1
index.ios.js
import React, { Component } from 'react';
import { AppRegistry, TextInput, View, Text } from 'react-native';
import { PasscodeTextInput } from './common';
export default class ProgressBar extends Component {
constructor() {
super()
this.state = {
autoFocus1: true,
autoFocus2: false,
autoFocus3: false,
autoFocus4: false,
}
}
onTextChanged(t) { //callback for immediate state change
if (t == 2) { this.setState({ autoFocus1: false, autoFocus2: true }, () => { console.log(this.state) }) }
if (t == 3) { this.setState({ autoFocus2: false, autoFocus3: true }, () => { console.log(this.state) }) }
if (t == 4) { this.setState({ autoFocus3: false, autoFocus4: true }, () => { console.log(this.state) }) }
}
render() {
const { centerEverything, container, passcodeContainer, testShit, textInputStyle } = styles;
return (
<View style={[centerEverything, container]}>
<View style={[passcodeContainer]}>
<PasscodeTextInput
autoFocus={this.state.autoFocus1}
onChangeText={() => this.onTextChanged(2)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus2}
onChangeText={() => this.onTextChanged(3)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus3}
onChangeText={() => this.onTextChanged(4)} />
<PasscodeTextInput
autoFocus={this.state.autoFocus4} />
</View>
</View>
);
}
}
const styles = {
centerEverything: {
justifyContent: 'center',
alignItems: 'center',
},
container: {
flex: 1,
backgroundColor: '#E7DDD3',
},
passcodeContainer: {
flexDirection: 'row',
},
}
AppRegistry.registerComponent('ProgressBar', () => ProgressBar);
There is a defaultProp for TextInput where one can focus after component mounted.
autoFocus
If true, focuses the input on componentDidMount, the default value is false. for more information please read the related Docs.
UPDATE
After componentDidUpdate it won't work properly. In that case, one can use ref to focus programmatically.
You cannot forward the ref to <TextInput> using that way because ref is one of the special props. Thus, calling this.refs.passcode2 will return you <PasscodeTextInput> instead.
Try change to the following to get the ref from <TextInput>.
PasscodeTextInput.js
const PasscodeTextInput = ({ inputRef, ... }) => {
...
return (
<View>
<TextInput
ref={(r) => { inputRef && inputRef(r) }}
...
/>
</View>
...
);
}
Then, assign the inputRef from <PasscodeTextInput> to a variable and use focus() to switch focus (it is not deprecated as of RN 0.41.2).
index.ios.js
return (
<PasscodeTextInput
autoFocus={true}
onChangeText={(event) => { event && this.passcode2.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode2 = r }}
onChangeText={(event) => { event && this.passcode3.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode3 = r }}
onChangeText={(event) => { event && this.passcode4.focus() }} />
<PasscodeTextInput
inputRef={(r) => { this.passcode4 = r }} />
);
P.S: event && this.passcode2.focus() prevents focus is switched when trying to clear the old passcode and enter a new one.
we handled this style of screen with a different approach.
Rather than manage 4 individual TextInputs and handle the navigation of focus across each one (and then back again when the user deletes a character), we have a single TextInput on screen but is invisible (ie. 0px x 0px) wide which has the focus, maxLength and keyboard configuration, etc.
This TextInput takes input from the user but can't actually been seen, as each character is typed in we render the entered text as a series simple View/Text elements, styled much similar to your screen above.
This approach worked well for us with no need to manage what the 'next' or 'previous' TextInput to focus next to.
You can use focus method onChangeText as Jason stated, in addition to that adding maxLength={1} can make you jump to the next input immediately without checking what's added. (just noticed its deprecated, but still this is how I solved my problem, and should do fine until v0.36, and this link explains how you should update the deprecated function).
<TextInput
ref="first"
style={styles.inputMini}
maxLength={1}
keyboardType="numeric"
returnKeyType='next'
blurOnSubmit={false}
placeholderTextColor="gray"
onChangeText={(val) => {
this.refs['second'].focus()
}}
/>
<TextInput
ref="second"
style={styles.inputMini}
maxLength={1}
keyboardType="numeric"
returnKeyType='next'
blurOnSubmit={false}
placeholderTextColor="gray"
onChangeText={(val) => {
this.refs['third'].focus()
}}
/>
...
Please notice that my use of refs are deprecated too, but I've just copied the code since I can guarantee you that was working back then (hopefully works now too).
Finally, the main issue with this type of implementation is, once you try to remove a number with backspace your focus will jump to next one, causing serious UX issues. However, you can listen for backspace key entry and perform something different instead of focusing to next input. So I'll leave a link here for you to further investigate if you choose to use this type of implementation.
Hacky Solution to Previously Described Issue: If you check what's entered in onChangeText prop before doing anything, you can jump to next input if the value is a number, else (that's a backspace), jump back. (Just came up with this idea, I haven't tried it.)
I think the issue is that onSubmitEditing is when you hit the "return" or "enter" key on the regular keyboard... there is not one of those buttons on the keypad.
Assuming you want each input to only have one character, you could look at the onChangeText and then check if text has length 1 and call focus if the length is indeed 1.
<TextInput
ref={input => {
this.nameOrId = input;
}}
/>
<TouchableOpacity
onPress={()=>{
this.nameOrId.focus()
}}
>
<Text>Click</Text>
</TouchableOpacity>
I solve with this code:
const VerifyCode: React.FC = ({ pass, onFinish }) => {
const inputsRef = useRef<Input[] | null[]>([]);
const [active, setActive] = useState<number>(0);
const onKeyPress = ({ nativeEvent }:
NativeSyntheticEvent<TextInputKeyPressEventData>) => {
if (nativeEvent.key === "Backspace") {
if (active !== 0) {
inputsRef.current[active - 1]?.focus();
return setActive(active - 1);
}
} else {
inputsRef.current[active + 1]?.focus();
return setActive(active + 1);
}
return null;
};
return (
<View style={styles.container}>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 0}
ref={(r) => {
inputsRef.current[0] = r;
}}
/>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 1}
ref={(r) => {
inputsRef.current[1] = r;
}}
/>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 2}
ref={(r) => {
inputsRef.current[2] = r;
}}
/>
<StyledInput
onKeyPress={onKeyPress}
autoFocus={active === 3}
ref={(r) => {
inputsRef.current[3] = r;
}}
/>
</View>
);
};
export default VerifyCode;
I put one ref in all the inputs, and when the onKeyPress fire, the function verify if have to go back or go to next input
Solved it by removing autoFocus={true} and setting timeout.
I have a popup as a functional component and using "current.focus()" with Refs like this:
const Popup = ({ placeholder, autoFocus, showStatus, }) => { const inputRef = useRef(null); useEffect(() => {
Platform.OS === 'ios'
? inputRef.current.focus()
: setTimeout(() => inputRef.current.focus(), 40); }, [showStatus]); return (
<View style={styles.inputContainer}>
<TextInput
style={styles.inputText}
defaultValue={placeholder}
ref={inputRef}
/>
</View> };

Focus style for TextInput in react-native

In React Native, how do you change the style of a textInput when it gets focus? Say I have something like
class MyInput extends Component {
render () {
return <TextInput style={styles.textInput} />;
}
};
const stylesObj = {
textInput: {
height: 50,
fontSize: 15,
backgroundColor: 'yellow',
color: 'black',
}
};
const styles = StyleSheet.create(stylesObj);
And I want to change the background color on focus to green.
This documentation leads me to believe that the solution is something like
class MyInput extends Component {
constructor (props) {
super(props);
this.state = {hasFocus: false};
}
render () {
return (<TextInput
style={this.state.hasFocus ? styles.focusedTextInput : styles.textInput}
onFocus={this.setFocus.bind(this, true)}
onBlur={this.setFocus.bind(this, false)}
/>);
}
setFocus (hasFocus) {
this.setState({hasFocus});
}
};
const stylesObj = {
textInput: {
height: 50,
fontSize: 15,
backgroundColor: 'yellow',
color: 'black',
}
};
const styles = StyleSheet.create({
...stylesObj,
focusedTextInput: {
...stylesObj,
backgroundColor: 'green',
}
});
Ignoring potential mistakes in the styles structuring, would this be considered correct way to handle it? It seems very verbose to me.
You can achieve this by passing in the onFocus and onBlur events to set and unset styles when focused and blurred:
onFocus() {
this.setState({
backgroundColor: 'green'
})
},
onBlur() {
this.setState({
backgroundColor: '#ededed'
})
},
And then, in the TextInput do this:
<TextInput
onBlur={ () => this.onBlur() }
onFocus={ () => this.onFocus() }
style={{ height:60, backgroundColor: this.state.backgroundColor, color: this.state.color }} />
I've set up a full working project here. I hope this helps!
https://rnplay.org/apps/hYrKmQ
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
TextInput
} = React;
var SampleApp = React.createClass({
getInitialState() {
return {
backgroundColor: '#ededed',
color: 'white'
}
},
onFocus() {
this.setState({
backgroundColor: 'green'
})
},
onBlur() {
this.setState({
backgroundColor: '#ededed'
})
},
render: function() {
return (
<View style={styles.container}>
<TextInput
onBlur={ () => this.onBlur() }
onFocus={ () => this.onFocus() }
style={{ height:60, backgroundColor: this.state.backgroundColor, color: this.state.color }} />
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
marginTop:60
}
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);
The best way to control the style when the element is focused / blurred is to create your own TextInput wrapper
export const MyAppTextInput = (props) => {
return (
<TextInput
{...props}
/>
);
};
Note that {...props} will pass in any property you already set or available for TextInput.
Then extend the above component by adding state to apply styles when focus / blur
export const MyAppTextInput = (props) => {
const [isFocused, setIsFocused] = useState(false);
return (
<TextInput
{...props}
style={[props.style, isFocused && {borderWidth: 5, borderColor: 'blue'}]}
onBlur={() => setIsFocused(false)}
onFocus={() => setIsFocused(true)}
/>
);
};
And remember when you use the component to bind the value like in the example (see value={passwordText}); otherwise the value will disappear on blur as a new render commences after the state change.
<MyAppTextInput
style={styles.input}
value={passwordText}
textContentType="password"
autoCompleteType="off"
secureTextEntry
onChangeText={text => {
setPasswordText(text);
}}
/>
You can of course avoid creating a wrapper but if you have more than one input it will create a mess in your input(s) parent components as you will have to add repeating logic.
Use refs, DirectManipulation and setNativeProps for more performance: https://facebook.github.io/react-native/docs/direct-manipulation.
class MyInput extends Component {
focusedInput = () => {
this.textInput.setNativeProps({
style: { backgroundColor: 'green' }
})
}
blurredInput = () => {
this.textInput.setNativeProps({
style: { backgroundColor: 'yellow' }
})
}
render () {
return <TextInput
ref={c => { this.textInput = c}}
style={styles.textInput}
onFocus={this.focusedInput}
onBlur={this.blurredInput} />
}
}
const stylesObj = {
textInput: {
height: 50,
fontSize: 15,
backgroundColor: 'yellow',
color: 'black',
}
}
const styles = StyleSheet.create(stylesObj)
This updates the TextInput component directly without re-rendering the component hierarchy.
You can create a state to keep track of the input-state and use that state to toggle the style. Here is a simple example
const App = () => {
const [isActive, setActive] = useState(false);
return (
<TextInput style={{ color: isActive ? 'black' : 'grey' }} onFocus={() => setActive(true)} onBlur={() => setActive(false)}/>
);
}
Nader Dabit´s pointed me to do something similar -- using the state for styles -- but I think it can be done in a cleaner way if you created separate styles for the focused and unfocused style and pass only the style ID as follows:
getInitialState() {
return { style: styles.textinput_unfocused }
}
onFocus() {
this.setState({ style: styles.textinput_focused })
}
onBlur() {
this.setState({ style: styles.textinput_unfocused })
}
in render -- referencing by styleID in this.state.style, note how the different styles are passed as an Array:
<TextInput
onBlur={ () => this.onBlur() }
onFocus={ () => this.onFocus() }
style={ [styles.textinput, this.state.style] } />
+ your stylesheet à la carte:
textinput_focused: {
backgroundColor: 'red',
color: 'white'
}
textinput_unfocused: {
backgroundColor: 'green'
}
Hey guys I kinda used everyones idea :p
#Felix gave me an idea that might be perhaps even cleaner. (I would have loved to not have included state though on this static component, just to change styling... But I am to new to this to figure that out.
here was my solution:
import React, { Component } from 'react';
import { StyleSheet, TextInput } from 'react-native';
class TxtInput extends Component {
constructor(props) {
super(props);
this.state = {
style: {},
};
}
onFocus = () => {
const state = { ...this.state };
state.style = {
borderStyle: 'solid',
borderColor: '#e74712',
};
this.setState(state);
}
onBlur = () => {
console.log('on ONBLUR')
const state = { ...this.state };
state.style = {};
this.setState(state);
}
render = () => <TextInput style={[styles.input, this.state.style]} onFocus={() => this.onFocus()} onBlur={() => this.onBlur()} />;
}
const styles = StyleSheet.create({
input: {
color: '#000000',
fontFamily: 'MuseoSans 700 Italic',
fontSize: 22,
borderRadius: 34,
borderStyle: 'solid',
borderColor: 'transparent',
borderWidth: 5,
backgroundColor: '#ffffff',
textAlign: 'center',
width: '25%',
},
});
export default TxtInput;
I added the style into an array, have all the actual input styling done on the first property of the array and the second one the nit picking of the focus and blue.
Hope it helps
For that propose I design this simple logic in functional component (it works the same in class components with the pertinents changes), it can be apply to several <textinputs/>. Below I leave an example:
// state
const [isFocused, setIsFocused] = useState({
name: false,
email: false,
phone: false,
})
// handlers
const handleInputFocus = (textinput) => {
setIsFocused({
[textinput]: true
})
}
const handleInputBlur = (textinput) => {
setIsFocused({
[textinput]: false
})
}
// JSX
<View style={styles.form} >
<TextInput
style={isFocused.name ? [styles.inputs, { borderColor: 'blue' }] : styles.inputs}
placeholder='Name'
placeholderTextColor={darkColors.text}
textContentType='name'
keyboardType='default'
onFocus={() => handleInputFocus('name')}
onBlur={() => handleInputBlur('name')}
/>
<TextInput
style={isFocused.email ? [styles.inputs, { borderColor: 'blue' }] : styles.inputs}
placeholder='Email'
placeholderTextColor={darkColors.text}
textContentType='emailAddress'
keyboardType='email-address'
onFocus={() => handleInputFocus('email')}
onBlur={() => handleInputBlur('email')}
/>
<TextInput
style={isFocused.phone ? [styles.inputs, { borderColor: 'blue' }] : styles.inputs}
placeholder='Phone'
placeholderTextColor={darkColors.text}
keyboardType='phone-pad'
onFocus={() => handleInputFocus('phone')}
onBlur={() => handleInputBlur('phone')}
/>
</View>
<TextInput
style={{ backgroundColor: 'white', height: 40, width: 100, alignItems: 'center'
}}
theme={{ colors: { placeholder: 'white', text: 'white', primary: 'white',
underlineColor: 'transparent', background: '#003489' } }}
/>
set initial value in function component
const [warnColor, setWrnColor] = useState("grey");
set this in text input
style={[styles.brdColor, { borderColor: warnColor }]}
set this in stylesheet
brdColor: {
height: 40,
borderColor: "grey",
borderBottomWidth: 1,
marginTop: heightToDp("2%"),
width: "100%",
}
Change TextInput border color on focus, by using react hooks useState and useCallback.
const [isFocused, setIsFocused] = useState(false);
const handleFocus = useCallback(() => {
setIsFocused(!isFocused);
}, [isFocused]);
let bcOnFocus = {
borderColor: isFocused ? '#000000' : '#cccccc',
};
<ScrollView>
<View>
<TextInput
placeholder="Text Field"
style={bcOnFocus}
onFocus={handleFocus}
/>
</View>
</ScrollView>

Categories