How can I get the text / value of a textinput by its ref? - react-native

In my parent I have this code:
So I render inside it my custom inputs by this way:
My doubt is how I can access on any part of this parent the text of each input using the ref. Someone can help me?
The textinput component:
https://gist.github.com/ThallyssonKlein/4e054bc368ebc153fbf9222e304ff887

I couldn't solve the problem, apparently there is no way to get this property in pure React-Native.
So I started using the TextInput component of the react-native-paper package. This way the same code worked, I can get the text now with this excerpt:
console.log(refContainerStep1.current.state.value);

use useRef() instead of createRef();
const textInput = useRef(null);
<TextInput
ref={textInput}
....../>

You can access the ref via refContainerStep1.current.
What you can then do is check the Prototype property to check which methods you can use.
I noticed there's a function called _getText which can be used to obtain a value.
An example of grabbing the value in an onPress:
const onPress = () => {
console.log(refContainerStep1.current.__proto__); // See available methods
console.log(refContainerStep1.current._getText()); // Grab the value
}

Do it that way
const onButtonClick = () => {
console.log('get value from parent')
console.log(ref1.current.props.value)
console.log(ref2.current.props.value)
};
Example in expo
Parent
import * as React from 'react';
import { Text, View, StyleSheet,TextInput } from 'react-native';
import Constants from 'expo-constants';
import MyTextInput from './components/AssetExample';
import { Card } from 'react-native-paper';
export default function App() {
const ref1 = React.createRef();
const ref2 = React.createRef();
const onButtonClick = () => {
console.log(ref1.current.props.value)
console.log(ref2.current.props.value)
};
return (
<View style={styles.container}>
<Card>
<button onClick={onButtonClick}>get value</button>
<MyTextInput label={'label 2'} secure={false} ref={ref1} />
<MyTextInput label={'label 1'} secure={true} ref={ref2} />
</Card>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
Child
import React, { useState, useEffect } from 'react';
import { TextInput as RnTextInput, StyleSheet, View, Text } from 'react-native';
const styles = StyleSheet.create({
textInput: {
padding: 10,
marginRight: 10,
marginLeft: 10,
borderRadius: 50,
},
text: {
marginLeft: 20,
marginBottom: 10,
fontSize: 20,
},
});
const TextInput = React.forwardRef((props, ref) => {
const [text, setText] = useState('');
return (
<View>
{props.label && <Text style={styles.text}>{props.label}</Text>}
<RnTextInput
style={styles.textInput}
value={text}
onChange={(e) => {
setText(e.target.value);
}}
secureTextEntry={props.secure}
ref={ref}
/>
</View>
);
});
export default TextInput;

Related

Why is MyContext.Provider not showing value in render?

I am a newbie trying to work with react native context. A very simple program, but unable to show the value.
Here is the code:
import React, {Component} from 'react';
import {Text, View } from 'react-native';
export const MyContext = React.createContext();
export default class App extends Component {
static contextType = MyContext;
render() {
this.state = 1
return (
<View>
<Text> Hello There </Text>
<MyContext.Provider value={this.state}>
{this.props.children}
</MyContext.Provider>
</View>
);
};
};
'Hello There' gets displayed. Even if I hard-code the value for MyContext.Provider , it doesn't display anything, and there are no errors either. What am I doing wrong?
Here is an sample with a class component.
You have to create a context React.createContext
You have to apply your context with MyContext.Provider
You have to consume your context with MyContext.Consumer
import { Text, View } from 'react-native';
export const MyContext = React.createContext();
export default class App extends Component {
state = { value: 12};
render() {
return (
<MyContext.Provider value={this.state}>
<View
style={{ justifyContent: 'center', alignItems: 'center', flex: 1 }}>
<Text>Hello There </Text>
<MyContext.Consumer>
{({ value }) => <Text>{value}</Text>}
</MyContext.Consumer>
</View>
</MyContext.Provider>
);
}
}
Kindly check context example. hope it helps
Please check the working example here https://snack.expo.dev/#gaurav1995/excited-donut
import React,{useContext,useState,createContext} from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
const BasicContext = createContext({})
const BasicComp = () => {
const dummyText = useContext(BasicContext);
return(
<View style={styles.container} >
<Text>{dummyText?.hey}</Text>
</View>
)
}
export default function App() {
const [reach,setReach] = useState({ hey:"whatsup devs! loving context"})
return (
<BasicContext.Provider value={reach} >
<BasicComp />
</BasicContext.Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});

Unable to Apply Layout Animation Using Reanimated API

I'm trying to apply layout animation to a FlatList upon adding and deleting a goal (list item) using the Reanimated API. I'm mainly following this tutorial from the Reanimated docs but I don't know why the animation is not applied when list items are added or removed. I should also inform that I'm only testing this on an Android device. Here is the code:
App.js (contains FlatList)
import { useState } from "react";
import { Button, FlatList, StyleSheet, View } from "react-native";
import GoalInput from "./components/GoalInput";
import GoalItem from "./components/GoalItem";
export default function App() {
const [goalList, setGoalList] = useState([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const styles = StyleSheet.create({
appContainer: {
paddingTop: 50,
},
});
function startAddGoalHandler() {
setIsModalOpen(true);
}
// spread existing goals and add new goal
function addGoalHandler(enteredGoalText) {
setGoalList((currentGoals) => [
...currentGoals,
{ text: enteredGoalText, id: Math.random().toString() },
]);
}
function deleteGoalHandler(id) {
setGoalList((currentGoals) =>
currentGoals.filter((existingGoals) => existingGoals.id !== id)
);
}
return (
<View style={styles.appContainer}>
<Button
title='Add New Goal'
color='indigo'
onPress={startAddGoalHandler}
/>
{isModalOpen && (
<GoalInput
isModalOpen={isModalOpen}
setIsModalOpen={setIsModalOpen}
onAddGoal={addGoalHandler}
></GoalInput>
)}
<FlatList
keyExtractor={(item, index) => {
return item.id;
}}
data={goalList}
renderItem={(itemData) => {
return (
<GoalItem
onGoalDelete={deleteGoalHandler}
itemData={itemData}
/>
);
}}
/>
</View>
);
}
GoalItem.js (list item)
import React from "react";
import { Pressable, StyleSheet, Text } from "react-native";
import Animated, { Layout, LightSpeedInLeft, LightSpeedOutRight } from "react-native-reanimated";
const GoalItem = ({ itemData, onGoalDelete }) => {
const styles = StyleSheet.create({
goalCards: {
elevation: 20,
backgroundColor: "white",
shadowColor: "black",
height: 60,
marginHorizontal: 20,
marginVertical: 10,
borderRadius: 10,
},
});
return (
<Animated.View
style={styles.goalCards}
entering={LightSpeedInLeft}
exiting={LightSpeedOutRight}
layout={Layout.springify()}
>
<Pressable
style={{ padding: 20 }}
android_ripple={{ color: "#dddddd" }}
onPress={() => onGoalDelete(itemData.item.id)}
>
<Text style={{ textAlign: "center" }}>
{itemData.item.text}
</Text>
</Pressable>
</Animated.View>
);
};
export default GoalItem;
I've even tried replacing the FlatList with View but to no avail. I suspect that Reanimated isn't properly configured for my project, if I wrap some components with <Animated.View>...</Animated.View> (Animated from Reanimated and not the core react-native module) for example the child components will not show. Reanimated is installed through npm
Any help is appreciated, thanks!

React Native Snap Carousel Functional Component Issue

I'm using this snack as a template for implementing my own carousel component. This template is using Class Component and I converted it to a Functional component
https://snack.expo.io/#bd-arc/react-native-snap-carousel-%7C-example-with-custom-interpolations
I added this to my project and I believe some error is happening when rendering the Carousel but I'm unable to tell. It renders - but not all the components are rendering. I have only changed the Carousel itself to a function component. The problem is the is not showing below the Carousel - also if I add multiple VideoCarousel's, only the first one displays.
My code is below
App.js
import React from 'react';
import { View } from 'react-native';
import Header from './components/header';
import VideoCarousel from './components/videoCarousel';
import tailwind from 'tailwind-rn';
const App = () => {
return (
<View style={tailwind('flex pt-12 items-center bg-gray-300 h-full')}>
<Header />
<VideoCarousel />
<VideoCarousel />
</View>
)
};
export default App;
VideoCarousel.js
import React, { useState } from 'react';
import { Text, View, Dimensions, StyleSheet, Alert } from 'react-native';
import Carousel from 'react-native-snap-carousel'; // Version can be specified in package.json
import { scrollInterpolator, animatedStyles } from './../utils/animations';
const SLIDER_WIDTH = Dimensions.get('window').width;
const ITEM_WIDTH = Math.round(SLIDER_WIDTH * 0.7);
const ITEM_HEIGHT = Math.round(ITEM_WIDTH * 3 / 4);
const DATA = [];
for (let i = 0; i < 10; i++) {
DATA.push(i)
}
const VideoCarousel = () => {
const [index, setIndex] = useState(0);
_renderItem = (index) => {
return (
<View style={styles.itemContainer}>
<Text style={styles.itemLabel}>{`Item ${index.index}`}</Text>
</View>
);
}
return (
<View>
<Carousel
data={DATA}
renderItem={this._renderItem}
sliderWidth={SLIDER_WIDTH}
itemWidth={ITEM_WIDTH}
containerCustomStyle={styles.carouselContainer}
inactiveSlideShift={0}
onSnapToItem={(index) => setIndex(index)}
scrollInterpolator={scrollInterpolator}
slideInterpolatedStyle={animatedStyles}
useScrollView={true}
/>
<Text style={styles.counter}>
Test
</Text>
</View>
);
}
const styles = StyleSheet.create({
carouselContainer: {
marginTop: 50
},
itemContainer: {
width: ITEM_WIDTH,
height: ITEM_HEIGHT,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'dodgerblue'
},
itemLabel: {
color: 'white',
fontSize: 24
},
counter: {
marginTop: 400,
fontSize: 30,
fontWeight: 'bold',
textAlign: 'center',
backgroundColor: "black",
}
});
export default VideoCarousel;

React native StyleSheet.create where should I put

I need to pass props into Styles. So I created StyleSheet inside the class. But normal practice would be to create StyleSheet outside from the class.
I want to know are there any performance drawbacks by having StyleSheet.create inside the class ?
import React from 'react'
import { StyleSheet, View } from 'react-native'
import { connect } from 'react-redux'
import { Text } from 'native-base'
import p from '../../assets/colors/pallets'
const EmptyContainer = (props) => {
const texts = props.texts
const styles = StyleSheet.create({
emptyContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 20,
backgroundColor: p.background2[props.theme],
},
text: {
color: p.text1[props.theme],
},
})
return (
<View style={styles.emptyContainer}>
{texts.map((text) => (
<Text style={styles.text} key={Math.random()}>
{text}
</Text>
))}
</View>
)
}
const mapStateToProps = (state) => {
const { theme } = state
return {
theme: theme.theme,
}
}
export default connect(mapStateToProps)(EmptyContainer)
Edited:
There are several ways to pass props into StyleSheet.
Having StyleSheet inside class itself.
Pass props as function parameter to styles i.e. styles(props.theme). emptyContainer
What would be the best way by considering the performance of the app ?

ReferenceError: Can't find variable: SearchBar in React Native

I got an error called "ReferenceError: Can't find variable: SearchBar". I tried to check for syntax error and run the app again. But the same error appeared. How can I rectify it? Thanks.
This is my SearchScreen.js file.
import React, { useState } from 'react';
import { StyleSheet, View, TextInput } from 'react-native';
const SearchScreen = () => {
const [term, setTerm] = useState('')
return (
<View>
<SearchBar
term={term}
onTermChange={(newTerm) => setTerm(newTerm)} />
</View>
);
}
const styles = StyleSheet.create({});
export default SearchScreen;
This is my SearchBar.js file.
import React from 'react';
import { StyleSheet, View, TextInput } from 'react-native';
import { EvilIcons } from '#expo/vector-icons'
const SearchBar = ({ term, onTermChange }) => {
return (
<View style = {styles.background}>
<EvilIcons style={styles.icon} name="search" />
<TextInput
value={term}
style={styles.input}
placeholder="Search"
onChangeText={newTerm => onTermChange(newTerm)} />
</View>
);
}
const styles = StyleSheet.create({
background: {
height: 50,
borderRadius: 6,
marginHorizontal: 15,
flexDirection: 'row',
alignItems: 'center'
},
input: {
flex: 1
},
icon: {
fontSize: 35,
alignSelf: 'center',
marginHorizontal: 15
}
});