react native click highlighted word - reactjs

I'm using react-native-highlight-words to highlight hashtagged words in my react-native app. It highlights required words properly but I want to make it clickable too which is not provided by this library. Means when I will click #positivewibes word, it redirect me to another page.
I've uploaded the image for reference here.
My Code
import Highlighter from 'react-native-highlight-words';
export default class LikeComponent extends Component {
constructor(props) {
super(props);
this.state = {
highlightWordArray: []
};
}
componentDidMount() {
postText = this.props.postData.details;
var regexp = new RegExp('#([^\\s]*)','g');
postText = postText.match(regexp);
if(postText != null) {
this.setState({highlightWordArray: postText});
}
}
render() {
return (
<Highlighter
highlightStyle={{color: 'red'}}
searchWords={this.state.highlightWordArray}
textToHighlight= {this.props.postData.details}
/>
)}
}
Any help is appreciated. Thank you.

You can fork and modify the library code by providing an additional prop - onPress in the file as
<Text
onPress={props.onPress}
key={index}
style={chunk.highlight && highlightStyle}
>
{text}
</Text>
and later use it as
<Highlighter
...// other props
onPress={// your redirect instance}
/>

Related

How to modify an existing div element in html by react?

Is it possible to use react to show and hide an existing div element by id?
For example, I want use react to have this <div id="example">this is example</div> show and hide by button click and this element is not created by react.
First you need to understand React's philosophy. I strongly suggest you read the official React tutorial: https://reactjs.org/tutorial/tutorial.html.
In this case you would like to appear and disappear a div, this can be accomplished by changing internal state of a React Component. Then you need to create a function that is bound to the context of the instance of the Component.
For example:
class Example extends Component {
constructor(props) {
super(props);
this.state = {
open: true,
};
}
toggle() {
const { open } = this.state;
this.setState({
open: !open,
});
}
render() {
const { open } = this.state;
return (
<main>
<button onClick={this.toggle.bind(this)}>{open ? 'Hide' : 'Show'}</button>
{open && <div id="example"><h1>this is example</h1></div>}
</main>
);
}
}
Here's a codepen: https://codepen.io/anon/pen/PxWdZK?editors=1010

React Native binding functions over .map()

So I am having some trouble combining concepts of .map() and function binding. I am using .map() in the same way ngFor is used in angular, to place a custom button component on the page for every item in a user's account.
Here is some example code:
class MyButton extends Component {
constructor(props) {
super();
this.state = {
progress: 0
}
}
render() {
return(
<TouchableWithoutFeedback onPress={this.pressFunction}>
(...more code inside)
</TouchableWithoutFeedback>
)
}
pressFunction = () => {
(animate progress from 0 to 1 for some animation)
}
}
/////////////////////////////////////////////////////////////////
class Parent extends Component {
render() {
return(
{
this.props.data.array.map(obj => {
return(
<View style={someStyle}>
<MyButton data={obj} />
</View>
)
})
}
)
}
}
So in the Parent Component, multiple MyButtons are rendered properly, each according to the passed object from the array. However, when any button is pressed, all of the pressFunctions for all MyButtons fire.
My question is I guess, how do I ensure that each pressFunction of each MyButton is bound only to the specific instance of the MyButton? I am having trouble with the scope here.
My understanding is that
functionName = () => {}
should properly bind the function to the instance, but I have tried the older ways as well with the same result.
I solved this by creating a dynamic ref on each object mapped to a MyButton, using a unique property of each obj in the array:
this.props.data.array.map(obj => {
return(
<View style={someStyle}>
<MyButton ref={obj.name} data={obj} />
</View>
)
})
Still don't know why my it didn't bind uniquely without a ref
You should pass onPress as a props. Below is the updated code
class MyButton extends Component {
constructor(props) {
super();
this.state = {
progress: 0
}
}
render() {
return(
<TouchableWithoutFeedback onPress={this.props.onPress}>
(...more code inside)
</TouchableWithoutFeedback>
)
}
}
/////////////////////////////////////////////////////////////////
class Parent extends Component {
pressFunction = () => {
(animate progress from 0 to 1 for some animation)
}
render() {
return this.props.data.array.map(obj => {
return(
<View style={someStyle}>
<MyButton
data={obj}
onPress={this.pressFunction}
/>
</View>
)
})
}
}

component return white blank screen

I am trying to check if the user authorised the use of the camera and location and if he did not, then a simple screen should be render that let him know about it. The function getting invoked but the return statement return blank screen instead of the component.
NOTE :
I tried to use 'backgroundColor: 'black' ti see if the rendered and I can't even see the black background.
CODE:
componentWillMount() {
Permissions.checkMultiple(['camera', 'location']).then(response => {
//response is an object mapping type to permission
console.log('permission check')
console.log('response.camera', response.camera)
console.log('response.location', response.location)
if (response.camera === 'denied' || response.location === 'denied') {
return (
<View>
<Text>
Sorry you cant use this app without allowing Location and Camera permmision
to do it just go to Setting/Keepr and allow Location and Camera access for this app
</Text>
<Button title={'go to settings'} onPress={Permissions.openSettings}></Button>
</View>
)
}
})
}
You are trying to return a JSX in a componentWillMount... and inside the Promise callback. This simply won't work as you need to return JSX from render method. You can use the react-state to do that. Example:
class MyComponent extends React.Component {
constructor(props) {
this.state = {
response: {}
};
}
componentWillMount() {
Permissions.checkMultiple(["camera", "location"]).then(response => {
this.setState({ response });
});
}
render() {
const { response } = this.state;
if (response.camera === "denied" || response.location === "denied") {
return (
<View>
<Text>
Sorry you cant use this app without allowing Location and Camera
permmision to do it just go to Setting/Keepr and allow Location and
Camera access for this app
</Text>
<Button title={"go to settings"} onPress={Permissions.openSettings} />
</View>
);
}
return <p>something</p>;
}
}

How to access this.setstate in onShouldStartLoadWithRequest() of a WebView in React Native?

I'm really struggling to understand how to read and set this.state inside of functions called by WebView when doing specific operations. My end goal is to:
Show a activity indicator when the user clicks a link inside the webview
Perform certain actions based on the URL the user is clicking on
I'm very new to React, but from what I've learned, I should use () => function to bind this from the main object to be accessible inside the function.
This works on onLoad={(e) => this._loading('onLoad Complete')} and I can update the state when the page loaded the first time.
If I use onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest} I can see that it works and my console.warn() is shown on screen. this.state is of course not available.
However if I change it to onShouldStartLoadWithRequest={() => this._onShouldStartLoadWithRequest} the function doesn't seem to be executed at all, and neither this.state (commented in the code below) or console.warn() is run.
Any help is appreciated!
import React, { Component} from 'react';
import {Text,View,WebView} from 'react-native';
class Question extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
debug: 'Debug header'
};
}
render() {
return (
<View style={{flex:1, marginTop:20}}>
<Text style={{backgroundColor: '#f9f', padding: 5}}>{this.state.debug}</Text>
<WebView
source={{uri: 'http://stackoverflow.com/'}}
renderLoading={this._renderLoading}
startInLoadingState={true}
javaScriptEnabled={true}
onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest}
onNavigationStateChange = {this._onShouldStartLoadWithRequest}
onLoad={(e) => this._loading('onLoad Complete')}
/>
</View>
);
}
_loading(text) {
this.setState({debug: text});
}
_renderLoading() {
return (
<Text style={{backgroundColor: '#ff0', padding: 5}}>_renderLoading</Text>
)
}
_onShouldStartLoadWithRequest(e) {
// If I call this with this._onShouldStartLoadWithRequest in the WebView props, I get "this.setState is not a function"
// But if I call it with () => this._onShouldStartLoadWithRequest it's not executed at all,
// and console.warn() isn't run
//this.setState({debug: e.url});
console.warn(e.url);
return true;
}
}
module.exports = Question;
To access correct this (class context) inside _onShouldStartLoadWithRequest, you need to bind it with class context, after binding whenever this method will get called this keyword inside it will point to react class.
Like this:
onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest.bind(this)}
or use arrow function like this:
onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest}
_onShouldStartLoadWithRequest = (e) => {...}
Or like this:
onShouldStartLoadWithRequest={(e) => this._onShouldStartLoadWithRequest(e)}
Check this answer for more details: Why is JavaScript bind() necessary?

Appended React Native component not rerendering

I'm attempting to write a function to remove a React Native component (named "Card") from the DOM on-click, then append a new "Card" of the same class with different properties. For example, both Cards have background colors. If the first Card is green, the second Card, which should have a blue background, will inherit the green background of the original Card.
The Cards receive their background color passed as props, like so:
class Card extends Component {
constructor(props) {
super(props);
this.state = {
style: {
backgroundColor: this.props.card.backgroundColor
}
};
}
render() {
return (
<TouchableHighlight style={this.state.style}>
<Image source={this.props.card.img} />
</TouchableHighlight>
)
}
}
The main component looks like this:
class SetProject extends Component {
constructor(props) {
super(props);
this.state = {
cardArray: [{backgroundColor: 'green', img: require('~/SetProject/cardImages/ovals/1-red-empty-oval.png')}]
}
}
removeCard(){
let emptyArray = [];
this.setState({cardArray: emptyArray});
}
changeCard(){
// let emptyArray = [];
// this.setState({cardArray: emptyArray});
let newCardArray = [{backgroundColor: 'red', img: require('~/SetProject/cardImages/ovals/1-purple-shaded-oval.png')}]
this.setState({cardArray: newCardArray});
}
render() {
let cardElementArray = this.state.cardArray.map(theCard => {
return (
<Card card={theCard}></Card>
);
});
return (
<View>
<View>
{cardElementArray}
</View>
<TouchableHighlight>
<Text onPress={this.removeCard.bind(this)}>Remove Card</Text>
</TouchableHighlight>
<TouchableHighlight>
<Text onPress={this.changeCard.bind(this)}>Change Background</Text>
</TouchableHighlight>
</View>
);
}
}
So I've got two buttons: removeCard, which works great, and changeCard. If I press "Remove Card" and then press "Change Card," I see the exact results I'm looking for. The card is removed and is replaced by a new one. However, if I comment in these lines in changeCard:
// let emptyArray = [];
// this.setState({cardArray: emptyArray});
and press "Change Card" without pressing "Remove Card," the new Card has a new image but it keeps the background color of the previous Card. This also happens if I call this.removeCard() from changeCard.
In summary, I'd like to be able to perform the behavior of both of these functions simultaneously, but I'm only able to remove a Card and add a new, correctly rendered Card if I press both buttons separately.
Any ideas would be much appreciated!
Here you're using props for setting image but not setting style. You can use props as well. You have set the style in constructor. Then you want to change style but constructor is not called again but creating a new object.
You can use props setting styl as well
render() {
return (
<TouchableHighlight style={this.props.card.style}>
<Image source={this.props.card.img} />
</TouchableHighlight>
)
}
For better implementation in case properties of card gets more complex add an id property to card. You can use componentWillReceiveprops by this way unnecessary renders are neglected as well.
[{id:'1', backgroundColor: 'red', img:
require('~/SetProject/cardImages/ovals/1-purple-shaded-oval.png')}]
class Card extends Component {
constructor(props) {
super(props);
this.state = {
style: {
card: this.props.card
}
};
}
componentWillReceiveProps(nextProps){
if(nextProps.card.id != this.state.card.id)
{
setState({card:nextProps.card})
}
}
render() {
return (
<TouchableHighlight style={this.state.style}>
<Image source={this.props.card.img} />
</TouchableHighlight>
)
}
}
https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops
Don't you get warning about missing keys in array? Use unique identifier (or it's index in array as last resort) for each card, and use it to set key prop on each item in array. This way, when card in array changes, react can re-render it, because it's a new card to it.
let cardElementArray = this.state.cardArray.map(theCard => {
return (
<Card key={theCard.id} card={theCard}></Card>
);
});
Read more about keys here in React docs.

Resources