Trouble with custom react component - react-native

Having a go at making my first react native component. I am trying to build a component that reverses the strings passed to it. It works perfectly fine when I give it a hard coded string, but it dosen't seem to do anything when I pass it a string from a "TextInput" component.
Here is what I think are the relevant bit of code.
class ReverseText extends Component {
constructor(props) {
super(props);
this.state = {text: props.src};
}
reverseString = (str) =>{
let newString = "";
for (let i = str.length - 1; i >= 0; i--) {
newString += str[i];
}
return newString;
};
render() {
let display = this.reverseString(this.state.text);
return (
<Text>{display}</Text>
);
}
}
export default class PizzaTranslator extends Component {
constructor(props) {
super(props);
this.state = {text: ''};
}
render() {
return (
<View style={{padding: 10}}>
<TextInput
style={{height: 40}}
placeholder="Type here to translate2!"
onChangeText={(text) => this.setState({text})}/>
<Text style={{padding: 10, fontSize: 42}}>
{/*{this.state.text.split(' ').map((word) => word && '🍕').join(' ')}*/}
{this.state.text} /* this works */
</Text>
<ReverseText src="123" /> /* this works */
<ReverseText src={this.state.text} /> /* this dosen't works */
</View>
);
}
}
Why does the component work when I pass it a hard coded string, but fails when I pass it a string that I get from the TextInput?

The class ReverseText are just setting the state at first time receive the this.props.src. So, when you change the this.props, nothing happen.
To fix you could do this:
export default class ReverseText extends Component{
constructor(props) {
super(props);
this.state = {reverseText: ''};
}
componentWillReceiveProps(nextProps){
this.setState({reverseText: this.reverseString(nextProps.src)})
}
reverseString = (str) =>{
let newString = "";
for (let i = str.length - 1; i >= 0; i--) {
newString += str[i];
}
return newString;
};
render() {
return (
<Text>{this.state.reverseText}</Text>
);
}
}

Related

How do I clear placeholder text when using a ref in React Native?

I have a TextInput component gets reused in a few different places:
export default class SomeTextInput extends Component {
constructor(props) {
super(props);
}
render() {
let fontWeight = this.props.fontWeight ? this.props.fontWeight : 'Light';
let fontName = this.props.fontName ? this.props.fontName : 'Montserrat';
let fontString = createFontString(fontName, fontWeight);
let applyFontFamily = { fontFamily: fontString };
let style = this.props.style.constructor === Array ? this.props.style : [this.props.style];
return (
<TextInput
ref={(ref) => {
this.textInput = ref
}}
{...this.props}
style={[applyFontFamily, ...style]}
onFocus={() => {
this.clearText();
console.log('show me this.textInput', this.textInput.props.placeholder)
}}
/>
)
}
clearText() {
this.textInput.clear();
console.log('is this being reached???')
}
focus() {
this.textInput.focus();
}
blur() {
this.textInput.blur();
}
}
I've also tried using clearTextOnFocus. I believe the best way to do this would be to change the placeholder to '', but I'm not sure how given that the placeholder text is taken from a prop that's been passed down.
edit: I'm going to add the code that #ravibagul91 suggested
export default class OVTextInput extends Component {
constructor(props) {
super(props);
// this.state = {
// placeholder: props.placeholder
// }
}
render() {
let fontWeight = this.props.fontWeight ? this.props.fontWeight : 'Light';
let fontName = this.props.fontName ? this.props.fontName : 'Montserrat';
let fontString = createFontString(fontName, fontWeight);
let applyFontFamily = { fontFamily: fontString };
let style = this.props.style.constructor === Array ? this.props.style : [this.props.style];
return (
<TextInput
ref={(ref) => {
this.textInput = ref
}}
{...this.props}
style={[applyFontFamily, ...style]}
onFocus={() => {
// this.setState({ placeholder: "" });
this.clearText();
}}
/>
)
}
clearText = () => {
console.log(this.textInput)
console.log('is this being reached???', this.textInput.value);
console.log('is this being reached???', this.textInput.placeholder);
this.textInput.placeholder = "";
this.textInput.value = "";
}
// focus = () => {
// this.textInput.focus();
// }
// blur = () => {
// this.textInput.blur();
// }
focus() {
this.textInput.focus();
}
blur() {
this.textInput.blur();
}
};
What you are currently doing is erasing the value of the text. Your Textinput looks like a prop for receiving and using values. Textinput does not currently have the ability to clear placeholders. If you make a proposal, you can use the status values to solve it.
export default class SomeTextInput extends Component {
constructor(props) {
super(props);
this.state={
placeholder: props.placeholder
}
}
....
<TextInput
ref={(ref) => {
this.textInput = ref
}}
placeholder={this.state.placeholder}
{...this.props}
style={[applyFontFamily, ...style]}
onFocus={() => {
this.setState({ placeholder : "" });
console.log('show me placeholder', this.state.placeholder)
}}
/>
You can directly clear the placeholder like,
this.textInput.placeholder = "";
Demo
Note: This is tested simply on input but same will work for TextInput.

How do I update Different Screens form another independent screen?

I have an App with a navigationbar with 2 Screens.
When i apply a function on Screen/Component 1 , I want to render or trigger a change in the Second Screen.
is there a way to either re-render the screen on Enter or to update the state of the other screen ?
Component one:
export default class HomeScreen extends React.Component {
constructor() {
super();
}
_onPress(){
try {
await AsyncStorage.setItem('value', 'changed Value');
} catch (error) {
console.log(error.message);
}
console.log("saved: " + this.state.userName )
}
render() {
return (
<View style={styles.container}>
<Button title="btn" onPress={() => this._onPress()} >
</Button>
</View>
)
}
component 2:
export default class SecondScreen extends React.Component {
constructor() {
super();
this.state = {some : ''}
}
async getValue () {
let recievedValue = '';
try {
let promise = await AsyncStorage.getItem('value') || 'cheeseCake';
promise.then((value) => recievedValue = value)
} catch (error) {
// Error retrieving data
console.log(error.message);
}
return recievedValue
}
render() {
var value= this.getValue();
return (
<View style={styles.container}>
<Text>
HERE CHANGED VALUE: {value}
</Text>
<Button onPress={()=> this.setState((prev)=> {some:'Thing'})}>
</Button>
</View>
)
}
When i press the Button on screen 1(HomeScreen) the value is saved.
But it only shows in the secont screen when I trigger a statechange via Button Press.
How do I render the screen when I visit the screen via navigation bar ?
Did you try EventEmiter?
Use this custom event listener: https://github.com/meinto/react-native-event-listeners
eg:
import { EventRegister } from 'react-native-event-listeners'
/*
* RECEIVER COMPONENT
*/
class Receiver extends PureComponent {
constructor(props) {
super(props)
this.state = {
data: 'no data',
}
}
componentWillMount() {
this.listener = EventRegister.addEventListener('myCustomEvent', (data) => {
this.setState({
data,
})
})
}
componentWillUnmount() {
EventRegister.removeEventListener(this.listener)
}
render() {
return <Text>{this.state.data}</Text>
}
}
/*
* SENDER COMPONENT
*/
const Sender = (props) => (
<TouchableHighlight
onPress={() => {
EventRegister.emit('myCustomEvent', 'it works!!!')
})
><Text>Send Event</Text></TouchableHighlight>
)

How can I compare two variable in onPress?

I am trying to create a changing pin screen and i was failed in comparing two variable that getting from the user (new pin and comfirm pin). The error show me that "this.state.newpin" is an undefined object.
class SettingScreen extends Component {
state = {
oldpin: '000000',
newpin: '',
secpin: ''
}
onPressButton(){
if( this.state.newpin == this.state.secpin){
ToastAndroid.show("Password Changed", ToastAndroid.SHORT);
this.setState({ oldpin : this.state.newpin})
}
else {
ToastAndroid.show("Password Unmatched", ToastAndroid.SHORT);
}
}
handleNewPin = (text) => {
this.setState({ newpin: text })
}
handleSecPin = (text) => {
this.setState({ secpin: text })
}
...
<TextInput onChangeText = {this.handleNewPin} />
<TextInput onChangeText = {this.handleSecPin} />
<TouchableOpacity onPress={this.onPressButton}>
<Text> Change Password </Text>
</TouchableOpacity>
I can get the output for "this.state.newpin" and "this.state.secpin" from user.
I just failed in the comparing statement ( OnPressButton()).
I am new in React-Native.
Sorry for any inconvenience.
you just need to bind your onPressButton()func. in the constructor with this. and move your state to constructor like this;
class SettingScreen extends Component {
constructor(props) {
super(props);
this.state = {
oldpin: '000000',
newpin: '',
secpin: ''
};
this.onPressButton = this.onPressButton.bind(this);
}
}

TextInput block change in onChange (preventDefault)?

I have to have an uncontrolled text input (for some reason not detailed here). I am trying to block a change from happening in my <TextInput>.
Here is my component and here is Snack demo of it - https://snack.expo.io/#noitsnack/textinput-block-onchange
class UncontrolledInput extends Component {
inputRef = null
render() {
return (
<View>
<TextInput ref={this.refInput} onChange={this.handleChange} />
</View>
)
}
refInput = el => this.inputRef = el
handleChange = e => {
const { nativeEvent:{ text } } = e;
// block i characters
if (text.includes('i')) {
e.preventDefault();
e.stopPropagation();
e.returnValue = false;
return false;
}
}
}
Is this possible? While preventDefault and stopPoropagation exist in e they don't seem to do anything.
You just want the text not to update in certain situations? You can always bind it to a state value and determine whether the state value should update:
class UncontrolledInput extends Component {
state = {
text: '',
}
render() {
return (
<View>
<TextInput value={this.state.text} onChangeText={this.handleChange} />
</View>
)
}
handleChange = text => {
// only update if no 'i'
if (!text.includes('i')) {
this.setState({ text });
}
}
}

React Native - text input blinking when using state

I'm adding some validation to the input text of a TextInput component.
The TextInput's value is handled in the state and is only updated when the value entered is valid.
my code looks like so:
class TextInputWithValidation extends Component {
constructor(props) {
super(props);
this.state = { text: ''}
this.handleChange = this.handleChange.bind(this);
}
handleChange(text) {
if(isValid) {
this.setState({text})
}
}
render() {
return (
<TextInput
value={this.state.text}
onChangeText={this.handleChange}
/>
)
}
}
The problem is that when entering a non valid character to the TextInput the non valid text appears for a second and the disappears - what causes an unwanted blink.
Any ideas how to solve this?
Based on your comment, a work around could be to use your handleChange method to detect for a decimal point, and then simply set some sort of inputLengthState to the current location of the decimal
Then you can use the prop for text input maxLength = this.state.inputLengthState + this.state.precision, with precision being your decimal places. Ive written some basic code below
class TextInputWithValidation extends Component {
constructor(props) {
super(props);
this.state = {
text: '',
precision: 2,
inputLength: 100,
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(text) {
if(isValid) {
this.setState({text})
}
//somewhere here you would check text for a decimal place
//and then set the inputLength the decimals' string index. If null,
//set it to some limit however you would like ( i used 100 ).
}
render() {
return (
<TextInput
value={this.state.text}
maxLength={this.state.inputLength + this.state.precision}
onChangeText={(text) => {this.handleChange(text)}}
/>
)
}
}
Apologies if my code is a bit off syntax wise, it has been a little while. For the algorithm to check for the decimal place, I'm sure this should be pretty straight forward. If not, say.
you can try to use '=>' operator
class TextInputWithValidation extends Component {
constructor(props) {
super(props);
this.state = { text: ''}
this.handleChange = this.handleChange.bind(this);
}
//here
handleChange = (text) => {
if(isValid) {
this.setState({text})
}
}
render() {
return (
<TextInput
value={this.state.text}
//and here
onChangeText={() => this.handleChange}
/>
)
}
}