GetElementById equivalent in React Native - reactjs

I am working on creating a module for React-Native.
The module needs to highlight or point out certain elements on the screen based on configuration stored in a DB.
In Android, our database would consist of view ids and our code would highlight those view ids.
In HTML, the element Ids would be sufficient.
How do I define unique identifiers in React native.
These would be stored in a database and then highlighted in real-time. So the module would need to access the x, y, width and height of the elements in runtime
In HTML, I would use getElementbyId() and proceed to get its attributes. What would be the equivalent in React Native.
This works -
this.userNameRef.measure((width,height,fx,fy,px,py)=>{
console.log(fx)
console.log(fy)
})
If userNameRef is received as a string parameter, how can I get this data

First of all, have in your mind, the selection within React Native is different the web.
You don't select the element directly, you must take the reference through the prop of element.
All elements in React Native has a prop called ref, you will able to have access all informations about that component, you may call the methods and get properties values.
Example using class component:
class MyComponent extends React.Component {
onEndLoadImage = () => {
console.log(this.flatlist.current); // here have all methods and properties of Image
}
render() {
return (
<Image
ref={element => this.flatlist = element}
onLoadEnd={onEndLoadImage}
...
/>
);
}
}
Example using functional components with hooks:
function MyComponent {
const imageRef = useRef(null);
const onEndLoadImage = () => {
console.log(imageRef.current); // here have all methods and properties of Image
}
return (
<Image
ref={imageRef}
onLoadEnd={onEndLoadImage}
...
/>
);
}

You can use onLayout props on the required View to get the view dimensions on the React Native side.
import React from "react";
import {Text, View, StyleSheet} from "react-native";
const GetLayout = (props) => {
const _getLayout = (evt) => {
const data = evt.nativeEvent;
alert(JSON.stringify(data));
}
return(
<View style={{flex: 1}}>
<View style={{flex: 1}} onLayout={_getLayout}>
<Text>I am the required View</Text>
</View>
</View>
)
}
export default GetLayout;
const styles = StyleSheet.create({
})

Related

how to add ref from forwardref component without rendering?

I'm passing a dom node to a mapbox popup.
I've a component P.js which consists of forward ref as
import React from "react";
const P = React.forwardRef((props, ref) => {
return <p {...props} ref={ref}></p>
})
export default P;
I'm importing it in App.js as
import P from './P';
......
const pRef = useRef(null)
console.log(pRef)
const p = <P ref={pRef}/>
console.log(pREf)
const App = () => {
useEffect(() => {
..... //codes
marker.setPopup(new mapboxgl.Popup().setDOMContent(pRef.current))
})
}
How can i pass that ref rendering on another component and running in another?
In my case i tried to make another const to add value
const p = <P ref={pRef}/>
I think, this is not way to passing ref from another component, so it is not rendered.
Is there any methods in Marker component , that i can pass ref if instead to load dom content .
Thank you for helping.
I highly suggest using this react wrapper around the mapbox-gl named react-mapbox-gl
You can do the method mentioned in this tweet and put some style in your P tag to make it invisible by the way
<P class="hide">Hello world</P>
.hide { display: none } /* or any other that fits for you e.g. visibility hidden */
You can also use renderToString to convert your component to HTML string on the fly.
import * as React from 'react';
import { renderToString } from 'react-dom/server';
import mapboxgl from 'mapbox-gl';
const P = React.forwardRef((props, ref) => {
return <p {...props} ref={ref}></p>;
});
export default function App() {
React.useEffect(() => {
marker.setPopup(
new mapboxgl.Popup().setDOMContent(
// render your Paragraph component exactly to html
renderToString(<P>Hello world</P>),
),
);
});
return <div id="map" />;
}
Here is codesandbox for showing it works.
You can also pass the exact same string representation of your paragraph component suggested by a package doc
const popup = new mapboxgl.Popup()
.setHTML('<h1>Hello World!</h1>') // here is the string representation
.addTo(map);
If you want to work with the js package duo to legacy issue, there is also a package that helps you to add a custom tiny react wrapper around the package to work with called react-aptor

Pass the local image path as a prop between two functional components

I'm working on a project in react-native, where I have troubles of understanding how props works between functional components. My requirement is to create a re-usable button component where I can just pass the image location in the resource file inside my project, so it'll create the button for me. For some reason if i give the required location manually, it will work and create the button for me, but if i\I pass the location as a prop from where I create it wont work for some reason. My code as bellow.
Button component
import React, { Component } from 'react';
import {
View,
StyleSheet,
Image,
TouchableOpacity
} from 'react-native';
const ButtonWithImage = (props) => {
const {buttonStyle} = styles;
const clickEvent = () => {}
return (
<TouchableOpacity onPress= {clickEvent}style={buttonStyle}>
<Image
source={props.imagePath}
style={styles.ImageIconStyle}
/>
</TouchableOpacity>
);
};
const styles = {
buttonStyle: {
//alignSelf:'stretch',
height: 50,
width:50,
paddingTop:0,
flexDirection: 'row'
}
};
export default ButtonWithImage;
Place where I create the button and pass the prop
import React, { Component } from 'react';
import {
View,
StyleSheet,
Dimensions,
} from 'react-native';
import FooterIcons from './ButtonWithImage'
const Footer = () => {
return (
<View style={styles.footerStyle}>
<FooterIcons imagePath = {'./images/homeButton/homeBtn.png'} />
</View>
);
};
const styles = StyleSheet.create({
footerStyle: {
height: 60,
width: 100,
// justifyContent:'flex-start'
},
});
export default Footer;
This is not possible since you want to require an image with a local path
<Image source={require(props.path)} /> and this does not work because require can only take string literal as an argument.
This means that you will have to do:
<FooterIcons imagePath = {require('./images/homeButton/homeBtn.png')}
/>
To make it work.
And don't forget to give your image a width and height.
OR
You can do it in a way which works good for apps that does not have big amounts of images, because we will preload them:
1- Make an assets javascript file assets.js , this file should require all your local images, something like this:
const assetsObject = {
homeIcon: require('./images/homeButton/homeBtn.png')
boatIcon: require('./images/homeButton/boat.png')
....
...
}
module.exports = assetsObject
2- Now you need to require this file in your ButtonWithImage.js file
const assets = require('./assets.js')
const ButtonWithImage = (props) => {
const {buttonStyle} = styles;
const clickEvent = () => {}
return (
<TouchableOpacity onPress= {clickEvent}style={buttonStyle}>
<Image
source={assets[props.imagePath]}
style={styles.ImageIconStyle}
/>
</TouchableOpacity>
);
};
3- The props you send to ButtonWithImage should be on of the keys of the assetsObject we created 'homeIcon' or 'boatIcon' ..etc
const Footer = () => {
return (
<View style={styles.footerStyle}>
<FooterIcons imagePath = {'homeIcon'} />
</View>
);
};
4- Don't forget to give your image a width and height
Thats it, and i suggest not calling the prop imagePath anymore, maybe just image.
You can simply pass the value as you pass other pros.
import picture from 'linkOfYourImage.png';
function Func() {
<YourComponent imgLink={picture }/>
}

React Native. Getting value from ref attribute

I am trying to get value from a component but keep getting undefined refs.
Here is my code. From a function onClickSave(), I have tried to get this.refs to get a value of ref "input" in TextInputCell component but it's undefined. Is my code incorrect?
import React from 'react';
import { View, Text } from 'react-native';
import { Form, Section, TextInputCell } from 'react-native-forms';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import ActionBar3 from '../components/ActionBar3';
import * as profileActions from '../actions/profileActions';
const GLOBAL = require('../GlobalConstants');
class ProfileViewEdit extends React.Component {
constructor(props) {
super(props);
this.onClickSave.bind(this);
}
componentDidMount() {
console.log('componentDidMount');
}
onClickSave() {
console.log('aaabd');
console.log(this.refs);
}
render() {
const title = this.props.navigation.state.params.title;
let value = this.props.navigation.state.params.value;
return (
<View style={{ flex: 1, backgroundColor: '#EFEFF4' }}>
<ActionBar3
barTitle={title} navigation={this.props.navigation} onClickSave={this.onClickSave}
/>
<Section
title={title}
//helpText={'The helpText prop allows you to place text at the section bottom.'}
>
<TextInputCell
value={value}
ref="input"
/>
</Section>
</View>
);
}
}
const mapStateToProps = (state) => ({
stateProfile: state.profile
});
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(profileActions, dispatch)
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(ProfileViewEdit);
First thing that you are not handling events correctly. To use this in your events you need to bind this. Arrow functions bind it itself but you can bind manually to. More information is here.
You have to be careful about the meaning of this in JSX callbacks. In
JavaScript, class methods are not bound by default. If you forget to
bind this.handleClick and pass it to onClick, this will be undefined
when the function is actually called.
Second thing string refs are not suggested anymore. You should use functional ones. More info about that here.
Legacy API: String Refs
If you worked with React before, you might be familiar with an older
API where the ref attribute is a string, like "textInput", and the DOM
node is accessed as this.refs.textInput. We advise against it because
string refs have some issues, are considered legacy, and are likely to
be removed in one of the future releases. If you’re currently using
this.refs.textInput to access refs, we recommend the callback pattern
instead.
Example
<ActionBar3 barTitle={title} navigation={this.props.navigation} onClickSave={ () => this.onClickSave()} />
<TextInputCell value={value} ref={(ref) => { this.inputRef = ref; }} />

React Native - Invalid prop source passed to Image

I am completely new to react native dev, and I am trying to display and <Image>. I keep getting this error:
Warning: Failed prop type: Invalid prop source supplied to Image`
Here is what I have:
First, there is list of all images in project defined like this:
export const IMAGES = {
ScreenStart1: require('../../assets/img/app/startScreen/start1.jpg'),
}
This is the view which calls the image component:
import {IMAGES} from '../../shared/listOfImages'
import FullScreenImage from '../../components/fullScreenImage'
export default class StartScreen extends React.Component {
render (): React$Element<*> {
let src = IMAGES.ScreenStart1;
return (
<View style={{flex: 1}}>
<FullScreenImage src="{src}"/>
</View>
);
}
}
Finally the FullScreenImage component:
//this displays image in full screen
export default class FullScreenImage extends Component {
render (): React$Element<*> {
let src = this.props.src;
return (
<Image source={src} style={fullScreenImageStyle.container} resizeMode='cover'>
</Image>
);
}
}
Please can someone help me out?
I think your issue is <FullScreenImage src="{src}"/>, this literally passes down a string '{src}', if you want to inject a variable into a string you have to do this:
<FullScreenImage src={`${src}`}/>
But, is there a reason why you're not just doing <FullScreenImage src={src}/>?

React Native: Custom component w/ a function in a prop - Maximum call stack size exceeded

I have a custom component that wraps native <Text> component for a Limited Style Inheritance . In my custom component I have a function in the style prop to dynamically evaluate a custom font prop and decide what font to render.
This is my component:
import React from 'react';
import { Text } from 'react-native';
import styles from './styles';
const evaluateFont = (font = 'regular') => {
console.log('[evaluateFont]');
switch (font) {
case 'regular':
return styles.fontRegular;
case 'semibold':
return styles.fontSemibold;
case 'bold':
return styles.fontBold;
}
};
const MyText = (props) => {
const { children, style, font, ...rest } = props;
return (
<MyText>
<Text
style={[evaluateFont(font), style]}
{...rest}
>
{children}
</Text>
</MyText>
);
};
export default MyText;
But when running my app I get the Maximum call stack size exceeded Error.
Why my evaluateFont() fn cause this & keeps running?
Your problem is not your evaluateFont(), it's the <MyText></MyText> in your return statement that's creating a that's causing the stack issue. Try removing the extraneous <MyText></MyText> and see if that works any better.

Resources