const entryInput = forwardRef((props, ref) => {
return (
<View
style={{
fontFamily: "roboto-regular",
color: "rgba(255,0,0,0.6)",
fontSize: hp("1.5%")
}}>
<Text style={styles.text}>{props.show_err ? props.err : null}</Text>
<TextInput
ref={ref}
style={{
borderColor:
!props.err || props.err === "" || props.err === props.empty_err
? "gray"
: "rgba(255,0,0,0.6)",
backgroundColor: "rgba(213, 213, 213, 0.1)",
borderWidth: wp("0.3%"),
borderRadius: wp("1%"),
width: wp("85%"),
height: hp("5.2%"),
fontFamily: "roboto-regular",
fontSize: hp("2%"),
fontWeight: "normal"
}}
returnKeyType={props.last ? "done" : "next"}
blurOnSubmit={props.last ? true : false}
placeholderTextColor={"gray"}
paddingLeft={wp("2%")}
paddingRight={hp("2%")}
placeholder={props.placeholder}
onSubmitEditing={() => {
if (props.next_input) {
props.next_input.current.focus();
} else if (props.action) {
props.action();
}
}}
onChangeText={(text) => {
if (props.setText) props.setText(text);
if (props.validate) props.validate(text);
}}
/>
</View>
);});
New to react native... trying to create an input field for a password.
This custom component works great, but when I add the secureTextEntry={true} the font changes for no reason (it's not roboto-regular), it doesn't even change to the default font.
I noticed that when I remove the fontFamily key from the style object then save my code and the expo client reloads, then add fontFamily again and reload again the TextInput behaves as expected and the font is the one I set (roboto-regular), however the bug reappears when manually reloading the app.
The accepted answer will work on luck. The refs can be both defined or undefined when the component is being mounted.
Add the following to your component to properly solve the issue:
const _inputRef = useRef(null);
const setRef = useCallback((node) => {
if (_inputRef.current) {
// Make sure to cleanup any events/references added to the last instance
}
if (node) {
// Check if a node is actually passed. Otherwise node would be null.
// You can now do what you need to, setNativeProps, addEventListeners, measure, etc.
node.setNativeProps({
style: { fontFamily: "Quicksand-Medium" },
});
}
// Save a reference to the node
_inputRef.current = node;
}, []);
Make sure your TextInput has this ref assigned:
<TextInput ref={setRef} ... />
Adding the following to my custom component fixed the problem:
useEffect(() => {
if (ref) {
ref.current.setNativeProps({
style: { fontFamily: "roboto-regular" }
});
}
}, []);
Related
I'm using the react-native-gifted-chat package for my React Native application.
Somehow there is a space between the composer and the keyboard, although I did not customise the GiftedChat.
Marked orange in the attached screenshot:
I already tried to customise the composer or any other component, with not effect.
i'm also facing same problem after some time i find this solution and it's work for me.
<GiftedChat
isAnimated
messages={this.state.messages}
scrollToBottom={true}
renderUsernameOnMessage={true}
onSend={messages => this.onSend(messages)}
inverted={false}
isLoadingEarlier={true}
messagesContainerStyle={{ color: 'gray' }}
bottomOffset={0} // add this line and space is remove
renderBubble={props => {
return (
<Bubble
{...props}
textStyle={{
right: {
color: 'white',
},
left: {
color: '#24204F',
},
}}
wrapperStyle={{
left: {
backgroundColor: 'white',
},
right: {
backgroundColor: "#ff3b00", // red
},
}}
/>
);
}}
renderInputToolbar={props => {
return (<InputToolbar {...props} containerStyle={{ backgroundColor: '#e2e2e2' }} />);
}}
user={{
_id: 1
}}
/>
hope this willl work for you
bottomOffset={0} // add this line and space is remove
install react-native-iphone-x-helper
and add these lines according to your code.
import { getBottomSpace } from 'react-native-iphone-x-helper';
<GiftedChat
bottomOffset={getBottomSpace()}
...
/>
As found on the docs itself, simply get the insets:
const insets = useSafeAreaInsets();
<GiftedChat
bottomOffset={insets.bottom}
...
/>
This will fix your issue dynamically.
I have images associated with a counter and based on this increment or decrement in counter, a calculation is done and displayed in a text at the bottom.
The problem is that when I render, the images get rendered again and are loaded again and again and again. which I dont want.
If I dont render, the text will not update with the calculated amount.
For the counter I am using react-native-counter.
I have already tried with shouldcomponentupdate, but I want to stop only image rendering, the rest should work.
Please advise.
export default class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<Header
backgroundColor="#25D366"
leftComponent={
<Icon
name="menu"
size={40}
color={"#fff000"}
onPress={() => this.props.navigation.openDrawer()}
/>
}
centerComponent={{
text: "Veg & Fruits",
style: {
color: "#ffffff",
fontSize: 25,
fontWeight: "bold",
},
}}
rightComponent={<Icon name="home" color={"#ff0000"} />}
></Header>
/// this is searchbar component,
<SearchBar
fontColor="#ffffff"
fontWeight="bold"
fontSize={20}
iconColor="#c6c6c6"
shadowColor="#ffffff"
cancelIconColor="#c6c6c6"
backgroundColor="#25D366"
placeholder="Search here"
onChangeText={(text) => {
this.setState({ photos: [] });
this.state.search = text;
this.filterList(this.state.search);
console.log("text changed");
}}
onPressCancel={(text) => {
text = "";
//this.filterList(text);
}}
onPress={(text) => {
console.log("rendering");
console.log("now text is: ", this.state.search);
}}
/>
/// in this view images are displayed using functions
<View>
<ScrollView
style={{
height: Dimensions.get("window").height - 200,
}}
>
<View
key={Date.now()}
style={{
flex: 1,
flexDirection: "column",
flexWrap: "wrap",
}}
>
{this.filterList(this.state.search)}
{this._renderImages()}
</View>
</ScrollView>
<CalcText tt={total_num} />
</View>
</div>
);
}
}
class CalcText extends Component {
constructor(props) {
super(props);
this.state = {
ta: 0,
};
}
shouldComponentUpdate(nextProps) {
console.log(nextProps.tt);
if (this.props.tt !== nextProps.tt) {
console.log("changed");
return true;
} else {
console.log("Not changed");
return false;
}
}
render() {
return (
<View style={{ height: 40, backgroundcolor: "ff0000" }}>
<Text style={{ fontSize: 26, fontWeight: "bold" }}>
Total : {this.props.tt}
</Text>
</View>
);
}
}
You can create a TextBox component and split it from ImageComponent. In this way the images will not be bound to the state of the component rendering text, and you can safely change TextBox state and text preventing ImageComponent to re-render.
Edit:
Okei, now i get it. I think you have no possibility to do it like this.
Let's formalize the problem:
<Parent>
<Images calc={functionToCalc} />
<CalcText totalAmount={this.state.totalAmount}/>
</Parent>
functionToCalc is defined in in <Parent> and update parent state, something like:
const funcToCalc = () => {
// when condition occurs
this.setState({
totalAmount : computedAmount
})
}
The state of <Parent> has:
this.state : {
totalAmount: none
}
Whenever condition (buttonClick?) occurs in <Images/> you run functionToCalc update <Parent> state and rerender <CalcText>. Problem here is that also <Images> will be rerender again as all the parent component will be rerender.
this is one of the way to pass info from siblings in React.
You only have a possibility if you want to prevent <Images> rerendering.
Redux or similar libraries for centralize state
You will move the computed calculation in a Store and <CalcText/> will read that from there. <Images/> component will trigger an action modifying that state but won't listen to that so not being rerender.
I'm using TextInput to allow only numbers using state, it works on android but not on iOS. Here's how I'm using state to allow only numbers.
handleInputChange = (text) => {
if (/^\d+$/.test(text) || text === '') {
this.setState({
text: text
});
}
}
my render method
render = () => {
return (
<View style={{
flex: 0,
flexDirection: 'row',
alignItems: 'flex-end',
marginTop: 50
}}>
<View style={{ flex: 0, marginLeft: 10 }}>
<Text style={{ fontSize: 20}}>$</Text>
</View>
<View style={{flex: 1,}}>
<TextInput
onChangeText={this.handleInputChange}
value={this.state.text}
underlineColorAndroid='transparent'
autoCorrect={false}
spellCheck={false}
style={{ paddingLeft: 5, fontSize: 20 }} />
</View>
</View>
);
}
This only works in Android, I guess because the state has changed react doesn't update the ui.
pls try this:
keyboardType='numeric' in the tag TextInput
when you prove don't put the numbers with the keyboard of your pc, pls use the keyboard of the emulator
if still not working put this textContentType='telephoneNumber'
As Ravi Rupareliya said this's a bug, which TextInput doesn't update, when the state text is shorter than the current TextInput value. Seems like the bug has been fixed in react-native 0.57.RC. For now I'm using the following fix.
handleInputChange = (text) => {
const filteredText = text.replace(/\D/gm, '');
if(filteredText !== text) {
// set state text to the current TextInput value, to trigger
// TextInput update.
this.setState({ text: text });
// buys us some time until the above setState finish execution
setTimeout(() => {
this.setState((previousState) => {
return {
...previousState,
text: previousState.text.replace(/\D/gm, '')
};
});
}, 0);
} else {
this.setState({ text: filteredText });
}
}
React native not provided keyboardType which remove punctuation from keyboard. You need to use regular expression with replace method to remove punctuation from text and set keyboardType = 'numeric'.
Regular Expression
/[- #*;,.<>{}[]/]/gi
Example code
onTextChanged(value) {
// code to remove non-numeric characters from text
this.setState({ number: value.replace(/[- #*;,.<>\{\}\[\]\\\/]/gi, '') });
}
Please check snack link
https://snack.expo.io/#vishal7008/1e004c
Worked for me:
<TextInput
...
textContentType='telephoneNumber'
dataDetectorTypes='phoneNumber'
keyboardType='phone-pad'
/>
While having input from user you can change the keyBoard type for that particular text input box like this i.e. numeric or alphabatic etc...
<TextInput>
//contains some code
keyboardType="Numeric"
</TextInput>
<TextInput>
keyboardType="number-pad"
</TextInput>
onChangeText={value => setuserPrimaryPhone(value.replace(/[^0-9]/g, ''))}
javascript simple method replace(/[^0-9]/g, ''))}
I am using expo v27.0, react native 0.55 and I as you can see in the picture that the tab have somewhat a fixed width like a default width from the tab navigation, and the text wrap into three lines, I want the text to be in 1 line and nowrap, and i have tried styling (flexWrap:
'nowrap', flex: 1) in TabStyle, LabelStyle in TabBarOptions, but still can't get the tab to have the width according to the text inside the tab.
I populate the text for the tabs dynamically from json using fetch, therefore all tabs will have different width according to the text. How to I make the tab to follow the width of the text ?
All answers are greatly welcomed.
Thank you in advance.
Solved, turns out just need to set the width to auto as follows:
tabBarOptions: {
tabStyle: {
width: 'auto'
}
}
You can use render label in render header and in that you can return your Text component and Text is having numberOfLines props that will be 1 and it will add ... at end of the text after one line.
Check example snippet:
_renderLabel = props => {
let preparedProps = {
style: {
fontFamily: fonts.Regular,
marginVertical: 8
},
fontType: props.focused ? "Medium" : "Light"
};
return (
<Text
{...preparedProps}
numberOfLines={1}
ref={ref => {
ref && this.props.addAppTourTarget(ref, props.route.key);
}}
>
{props.route.type === "free" && this.state.is_premium_member
? this.labels.premium
: props.route.title}
</Text>
);
};
_renderHeader = props => (
<TabBar
{...props}
bounces={true}
style={{
backgroundColor: colors.cardBlue
}}
indicatorStyle={{
backgroundColor: colors.radicalRed,
height: 1,
borderRightWidth: initialLayout.width * 0.1,
borderLeftWidth: initialLayout.width * 0.1,
borderColor: colors.cardBlue
}}
tabStyle={{
padding: 0,
borderTopColor: "transparent",
borderWidth: 0
}}
renderLabel={this._renderLabel}
/>
);
_handleIndexChange = index => this.setState({ index });
_renderScene = ({ route, focused }) => {
switch (route.key) {
case "a":
return <One {...this.props} route={route} focused={focused} />;
case "b":
return (
<Two {...this.props} isSeries={true} focused={focused} />
);
case "c":
return <Three {...this.props} route={route} focused={focused} />;
default:
return null;
}
};
I want to directly update the value of a component due to performance reasons.
render(){
<View>
<Text style={styles.welcome} ref={component => this._text = component}>
Some Text
</Text>
<TouchableHighlight underlayColor='#88D4F5'
style={styles.button}>
<View>
<Text style={styles.buttonText}
onPress={this.useNativePropsToUpdate.bind(this)}>
Iam the Child
</Text>
</View>
</TouchableHighlight>
</View>
}
This is the method I use to update the text component. I dont know if I am setting the right attribute/ how to figure out which attribute to set:
useNativePropsToUpdate(){
this._text.setNativeProps({text: 'Updated using native props'});
}
Essentially trying to follow the same approach from this example:
https://rnplay.org/plays/pOI9bA
Edit:
When I attempt to explicitly assign the updated value:
this._text.props.children = "updated";
( I know this this the proper way of doing things in RN ). I get the error "Cannot assign to read only property 'children' of object'#'"
So maybe this is why it cant be updated in RN for some reason ?
Instead of attempting to change the content of <Text> component. I just replaced with <TextInput editable={false} defaultValue={this.state.initValue} /> and kept the rest of the code the same. If anyone know how you can change the value of <Text> using setNativeProps OR other method of direct manipulations. Post the answer and ill review and accept.
The text tag doesn't have a text prop, so
this._text.setNativeProps({ text: 'XXXX' })
doesn't work.
But the text tag has a style prop, so
this._text.setNativeProps({ style: { color: 'red' } })
works.
We can't use setNativeProps on the Text component, instead, we can workaround and achieve the same result by using TextInput in place of Text.
By putting pointerEvent='none' on the enclosing View we are disabling click and hence we can't edit the TextInput (You can also set editable={false} in TextInput to disbale editing)
Demo - Timer (Count changes after every 1 second)
import React, {Component} from 'react';
import {TextInput, StyleSheet, View} from 'react-native';
class Demo extends Component {
componentDidMount() {
let count = 0;
setInterval(() => {
count++;
if (this.ref) {
this.ref.setNativeProps({text: count.toString()});
}
}, 1000);
}
render() {
return (
<View style={styles.container} pointerEvents={'none'}>
<TextInput
ref={ref => (this.ref = ref)}
defaultValue={'0'}
// editable={false}
style={styles.textInput}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 0.7,
justifyContent: 'center',
alignItems: 'center',
},
textInput: {
fontSize: 60,
width: '50%',
borderColor: 'grey',
borderWidth: 1,
aspectRatio: 1,
borderRadius: 8,
padding: 5,
textAlign: 'center',
},
});
export default Demo;
As setNativeProps not solving the purpose to alter the content of <Text />, I have used below approach and is working good. Create Simple React Component like below...
var Txt = React.createClass({
getInitialState:function(){
return {text:this.props.children};
},setText:function(txt){
this.setState({text:txt});
}
,
render:function(){
return <Text {...this.props}>{this.state.text}</Text>
}
});