Get the childrens of an element in react native using useRef - react-native

I am trying to understand how to use useRef in React Native and get the children of a View element, but I couldn't figure out to achieve it.
I am trying to use the .focus method in the TextInput component on press on the TouchableOpacity
Declaration:
const input = useRef(null);
TextInputComponent:
<View ref={input}>
<Tex>Email</Text>
<TextInput placeholder=""/>
</View>
Element:
<TouchableOpacity onPress={() => {}}>
<TextInputComponent />
</TouchableOpacity>
i tried input.current.children, but it returns undefined.

This is a working example of how to achieve what you want using on a basic expo init project on TypeScript:
App.tsx
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, TextInput, TouchableOpacity} from "react-native";
import { useRef, forwardRef} from "react";
const TextInputComponent = forwardRef<TextInput>((props, ref) => {
return (
<View>
<Text>Email</Text>
<TextInput ref={ref} placeholder="Some placeholder" />
</View>
);
});
export default function App() {
const input = useRef<TextInput>(null)
return (
<View style={styles.container}>
<Text>Open up App.tsx to start working on your app!</Text>
<StatusBar style="auto" />
<TouchableOpacity onPress={() => {
input.current?.focus();
}}>
<TextInputComponent ref={input} />
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
In this case it is more practical to use a forwardRef so you don't have to loop through the children of the View component to pass a ref from the component (App in this case) that is using TextInputComponent.

Related

array values showing undefined in react native expo while working in web

The code is working in web version of react native but not in expo The array values are showing unefined but they are working fine in web version.Please tell me what is wrong here
import { View, Text, StyleSheet } from "react-native"
import React from "react"
import { FontAwesomeIcon } from "#fortawesome/react-native-fontawesome"
import { faEdit, faMinusSquare } from "#fortawesome/free-regular-svg-icons"
function List({ todoArr, handleModalOpen, removeItem }) {
console.log(todoArr)
return (
<>
{todoArr.map((item, index) => {
console.log(index)
return (
<View>
<Text key={item} style={styles.item}>{item}</Text>
<Text onPress={() => handleModalOpen(index, item)}>
<FontAwesomeIcon icon={faEdit} />
</Text>
<Text onPress={() => removeItem(index)}>
<FontAwesomeIcon icon={faMinusSquare} />
</Text>
</View>
)
})}
</>
)
}
const styles = StyleSheet.create({
item: {
fontSize: 20
},
})
export default List
import { ScrollView, StyleSheet, Text, View } from 'react-native';
import Buttons from './components/Add and Del Btn';
import EditModal from './components/EditModal';
import Heading from './components/Heading';
import Input from './components/Input';
import List from './components/List';
import Todo from './todo';
export default function App() {
let [indexNo , inpVal,updInpVal , todoArr,modalVisible ,setUpdInpVal , getInp, add, delAll, removeItem, editItem , handleModalClose , handleModalOpen] = Todo();
return (
<View style={styles.container}>
<EditModal modalVisible = {modalVisible} updInpVal={updInpVal} setUpdInpVal = {setUpdInpVal} editItem = {editItem} indexNo = {indexNo}/>
<View>
<Heading />
<View>
<Input getInp={getInp} inpVal={inpVal} />
<Buttons add={add} delAll={delAll} />
</View>
<View>
<List todoArr={todoArr} handleModalOpen={handleModalOpen} removeItem={removeItem} />
</View>
</View>
</View >
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});

React Navigation6 Header issue

i'm building application with ReactNative and Expo, i building component called Header showing the title of each screen,
so i send props of name on each time render the component
<Header title={"Home Screen"}/>
Header.js comoment
import React,{ useState } from 'react';
import { Text, View, Image,StyleSheet} from 'react-native';
import Icon from 'react-native-vector-icons/Feather';
import { useNavigation } from "#react-navigation/native";
const Header=( navigation, title) =>{
const { navigate } = useNavigation();
return(
<View style={styles.container}>
<Icon name="user" size={28}/>
<Text style={{fontWeight:'bold'}} >{title}</Text>
<Icon name="bell" size={28} />
</View>
)
}
export default Header;
const styles = StyleSheet.create({
container:{
position:"absolute",
display:'flex',
justifyContent: 'space-between',
flexDirection:'row',
height: 60,
top:10 ,
left:6,
right:6,
elevation:0,
backgroundColor: '#fff',
alignItems: 'center',
}
})
this error showing:
Error: Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead.
You just missed to de-structure your props in Header. Simply change your Header component to have
const Header=({ title }) =>{ // added {} to de-structure your props
const { navigate } = useNavigation();
return(
<View style={styles.container}>
<Icon name="user" size={28}/>
<Text style={{fontWeight:'bold'}} >{title}</Text>
<Icon name="bell" size={28} />
</View>
)
}

Expo / TouchableOpacity onPress() not responding

I'm trying to reproduce a pomodoro app from an online course.
I've been looking at my code for several hours, going back and forth with the course, but can't find my error.
TouchableOpacity or Pressable used in RoundedButton component doesn't trigger onPress()
I tried different command to test if my logic with setStarted was flawe, without success.
Anyone can help me find my bug ?
Here is the link to the expo : https://snack.expo.dev/#battlepoap/focus-time
RoundedButton.js:
import React from 'react';
import { TouchableOpacity, Text, StyleSheet, View } from 'react-native';
export const RoundedButton = ({
style = {},
textStyle = {},
size = 125,
...props
}) => {
return (
<View>
<TouchableOpacity style={[styles(size).radius, style]}>
<Text style={[styles(size).text, textStyle]}>{props.title}</Text>
</TouchableOpacity>
</View>
);
};
const styles = (size) =>
StyleSheet.create({...});
Example with Focus.js where we add a task by pressing on the RoundedButton :
import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { TextInput } from 'react-native-paper';
import { RoundedButton } from '../../components/RoundedButton';
import { fontSizes, spacing } from '../../utils/sizes';
export const Focus = ({ addSubject }) => {
const [tempSubject, setTempSubject] = useState(null);
return (
<View style={styles.container}>
<View style={styles.titleContainer}>
<Text style={styles.title}>What do you want to focus on ?</Text>
<View style={styles.inputContainer}>
<TextInput
style={{ flex: 1, marginRight: spacing.sm }}
onSubmitEditing={({ nativeEvent }) => {
setTempSubject(nativeEvent.text);
}}
/>
<RoundedButton
size={50}
title="+"
onPress={() => addSubject = tempSubject}
/>
</View>
</View>
</View>
);
};
sic In the additional files there was ....
One thing we however need to add in order to make sure the button triggers is the onPress method. This method allows us to trigger the touch event of the user. Don't forget it!!
<TouchableOpacity style={[styles(size).radius, style]}>
<Text
style={[styles(size).text, textStyle]}
onPress={props.onPress}>
{props.title}
</Text>
</TouchableOpacity>

ReactNative send style as props to component

I am new to learning React Native and I would like to build a (ReactNaive & Expo) application with a good interface look, How can I build a component and send style{backgroundColor} as props then render the component on Home
home.js
import React from 'react'
import { View, Text , Image , ScrollView} from 'react-native';
import { FlatList } from 'react-native-gesture-handler';
import { COLORS, SIZES,FONTS} from '../styles/theme.js';
import Category from '../components/Category.js';
import CategorySlider from '../components/CategorySlider'
const Home = () => {
function renderHeader(){
return(
<View
style = {{
flexDirection: 'row' ,
marginTop: 40,
marginBottom: 10,
paddingHorizontal:SIZES.padding,
alignItems : 'center'
}}
>
<View style={{flex:1}}>
<Text >Hello , Wafa</Text>
</View>
{/* Nonfiction Button */}
</View>
)}
return (
<View
style ={{
flex: 1,
backgroundColor: COLORS.white
}}
>
{/* HEADER */}
{renderHeader()}
{/* Content */}
<View style={{height:130 , marginTop:SIZES.margin}}>
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false}
>
<Category name='Balance' />
<Category name='Saving' style={COLORS.green} />
<Category name='Income' style={ COLORS.brown } />
<Category name='Loans' style={ COLORS.pink}/>
<Category name='Saving' style={ COLORS.pink}/>
<Category name='Saving' style={ COLORS.pink}/>
</ScrollView>
</View>
<CategorySlider/>
</View>
)
}
export default Home;
It is the component I want to render on home.js
Category.js
import React, { PureComponent } from 'react'
import { Text, View ,StyleSheet ,Image } from 'react-native'
import { backgroundColor } from 'react-native/Libraries/Components/View/ReactNativeStyleAttributes';
import { COLORS, SIZES,FONTS} from '../styles/theme.js';
export default class Category extends PureComponent {
render() {
return (
<View style={{marginLeft: SIZES.margin ,marginRight: SIZES.margin}}>
<View>
<View style={{
height: 60,
width: 60,
backgroundColor:COLORS.pink,
borderRadius: SIZES.radius,
}}>
<View />
<View>
<Image />
</View>
</View>
<Text
style={{textAlign:'center'}}
>
{this.props.name}</Text>
</View>
</View>
)
}
}
l made also File for Design system contains style I will repeat on the application.
theme.js:
import { Dimensions } from "react-native";
import { useFonts } from 'expo-font';
const { width, height } = Dimensions.get("window");
export const COLORS = {
green: "#68AB9F",
brown: "#c18e62",
pink: "#d99e96" ,
gray: "#383e42",
white: "#f5f7fc",
}
Here you're working on one with a Functional based component (home.js) and one with Class-based (Category.js). Standard is if first convert your Category component with functional then you can save that props to your Category component like:
import React, { useState } from 'react'
import { Text, View ,StyleSheet ,Image } from 'react-native'
import { backgroundColor } from 'react-native/Libraries/Components/View/ReactNativeStyleAttributes';
import { COLORS, SIZES,FONTS} from '../styles/theme.js';
const Category = (props) => {
const [backgroundColor, setBackgroundColor] = useState(props.style || null); //store your prop in state like this
const [name, setName] = useState(props.name || null);
return (
<View style={{marginLeft: SIZES.margin ,marginRight: SIZES.margin}}>
<View>
<View style={{
height: 60,
width: 60,
backgroundColor: backgroundColor,
borderRadius: SIZES.radius,
}}>
<View />
<View>
<Image />
</View>
</View>
<Text
style={{textAlign:'center'}}
>
{name}</Text>
</View>
</View>
)
}
export default Category;
Hope this works for you.
In your parent component take your style object in the wrapper of child component i.e.
function Parent(){
return (
<Child cssdata={{backgroundColor:'red',marginLeft:8}}/>
)
}
and in your child component take this data from props and applied to it
function Child(props){
return (
<View style={props.cssdata}></View>
)
}

How to reuse a UI element in react native

App.js
import React,{ Component } from 'react';
import { StyleSheet,TextInput, View, Button, Text } from 'react-native';
import Toast from 'react-native-simple-toast';
import TextItem from '.src/Components/Textviews/TextViewDisplay';
export default class App extends Component {
state = {
placeName : "",
titleText: "Text view"
}
placeNameChangeHandler = val =>{
this.setState({
placeName : val
})
}
placeSubmitHandler = () =>{
this.setState({
titleText: this.state.placeName.trim()
})
Toast.showWithGravity('This is a long toast at the top.', Toast.LONG, Toast.TOP)
}
render() {
return (
<View style={styles.rootContainer}>
<View style={styles.btnEditContainer}>
<View style ={styles.wrapStyle}>
<TextInput
style = {styles.textInputStyle}
value = {this.state.placeName}
onChangeText = {this.placeNameChangeHandler}
/>
</View>
<View style ={styles.wrapStyle}>
<Button
title="Add"
style ={styles.buttonStyle}
onPress ={this.placeSubmitHandler}/>
</View>
</View>
<View style={styles.textContainer}>
<View style ={styles.wrapStyle}>
<Text
style ={styles.textStyle}>
{this.state.titleText}
</Text>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
rootContainer: {
height:"100%",
width:"100%",
backgroundColor: "#008000",
flexDirection:"column",
alignItems:"center",
justifyContent: "center"
},
btnEditContainer: {
backgroundColor:"#008080",
flexDirection:"row",
alignItems:"center",
justifyContent: "center"
},
textContainer: {
backgroundColor:"#00FFFF",
flexDirection:"column",
alignItems:"center",
justifyContent: "center"
},
textStyle: {
fontSize: 20,
flexDirection:"column",
alignItems:"center",
justifyContent: "center"
},
buttonStyle: {
//flex:1
},
textInputStyle: {
borderColor:"black",
borderWidth:1,
},
wrapStyle: { marginLeft:5,
marginRight:5 },
});
TextViewDisplay.js
import React from 'react';
import {StyleSheet, View, Text} from 'react-native';
const textItem = (props) => (
<View style={styles.rootElement}>
<Text style={styles.textItem}>
{props.textItem}
</Text>
</View>
);
const styles = StyleSheet.create({
rootElement : {
backgroundColor:"red"
},
textItem : {
color: '#f44336'
}
});
export default textItem;
What I am trying to do:
Instead of Text in App.js file I have written a
TextViewDisplay.js file to reuse.
How to properly implement in render function of App.js
If I undrestood your query correctly, then you just want to replace this
<Text style ={styles.textStyle}>
{this.state.titleText}
</Text>
from your App component with your TextItem (re-usable) component.
As you have already imported your TextItem component, you can do this way
<View style={styles.textContainer}>
<View style ={styles.wrapStyle}>
//This is your re-usable component
<TextItem style = {styles.textStyle}>
{this.state.titleText}
</TextItem >
</View>
</View>
And you just need to change {props.textItem} to {props.children} in your TextItem component.
<View style={styles.rootElement}>
<Text style={{...props.style, ...styles.textItem}}> //Here you can get style from your parent component
{props.children} //This is the child element
</Text>
</View>
Note: Always use PascalCase names for your component.
If you don't want to work with {props.children} and only want to work with {props.textItem}, in that case you need to pass props,
<TextItem style = {styles.textStyle} textItem = {this.state.titleText} />
Now you can use {props.textItem},
<View style={styles.rootElement}>
<Text style={{...props.style, ...styles.textItem}}> //Here you can get style from your parent component
{props.textItem}
</Text>
</View>
Just import your component and instantiate it in any render function:
import textItem from './TextViewDisplay';
render() {
return (
<View style={styles.rootContainer}>
<textItem textItem={'label'} />
...
</View>
}
I would suggest defining the component upper camel case though:
const MyTextItem = (props) => (...)
And giving the property a more meaningful name:
<MyTextItem label={'label'} />
Finally, it's also good to define property types, so other users of your component known which properties to pass, and what type they should be. For example as such:
import PropTypes from 'prop-types';
MyTextItem.propTypes = {
label: PropTypes.string.isRequired,
}
It's very simple re using components in react native :
Step - 1 : Import the function to the screen where you want to reuse that.
ex : import {textItem} from '../pathName'
Step -2 :
render() {
return (
//Create the component of the UI and then use it in render and don't forget to import that:
<TextItem
textItem = 'happy Coding'
/>
)}
Also make sure the component name starts with capital letter.