Why is the data undefined in react component? - javascript

So I'm trying to reproduce a simple example code of react-qr-scanner, but in the code below as I try to embed result in the p tag I get an error, saying objects cannot be embedded inside that. What am I doing wrong?
import React, { Component } from 'react';
import QrReader from 'react-qr-scanner';
class Scan extends Component {
constructor(props) {
super(props);
this.state = {
result : 'Hold QR Code steady and clear to scan',
}
this.previewStyle = {
height : 700,
width : 1000,
display : 'flex',
justifyContent : "center",
}
this.camStyle = {
display : 'flex',
justifyContent : 'center',
marginTop : '-50px',
}
this.textStyle= {
fontSize : '30px',
"text-align" : 'center',
marginTop : '-50px',
}
this.handleScan = this.handleScan.bind(this);
}
handleScan(data) {
this.setState({
result : data,
});
}
handleError(err) {
console.log(err);
}
render() {
return (
<>
<div className="stream-container" >
<QrReader
delay={100}
onError={this.handleError}
onScan={this.handleScan}
/>
</div>
<p style={this.resultStyle}>
{this.state.result} //here error occurs saying I cannot embed it inside here
</p>
</>
);
}
}
export default Scan;
The docs of react-qr-scanner has this exact example, so why isn't it working on mine? Please help.

In the function of handleScan, data is an object, 'Objects are not valid as a React child'.

Try to make your fuctions with arrow -
handleScan = (data) => {
this.setState({
result: data,
});
}
handleError = (err) => {
console.log(err);
}

Related

In React SharePoint WebPart what are the differences between using 'html-react-parser' & using 'dompurify eslint-plugin-risxss' to securely show HTML

I am trying to build a React.js SharePoint modern web part, which have the following capabilities:-
Inside the Web Part settings page >> there are 2 fields named as "Who We Are" & "Our Value" which allow the user to enter HTML.
The web part will render 2 buttons "Who We Are" & "Our Value" >> and when the user clicks on any button >> a Popup will be shown with the entered HTML code in step-1
Something as follow:-
But to be able to render HTML code as Rich-Text inside my Web Part, i have to use the dangerouslySetInnerHTML attribute inside the .tsx file. as follow:-
import * as React from 'react';
import { useId, useBoolean } from '#fluentui/react-hooks';
import {
getTheme,
mergeStyleSets,
FontWeights,
Modal,
IIconProps,
IStackProps,
} from '#fluentui/react';
import { IconButton, IButtonStyles } from '#fluentui/react/lib/Button';
export const MYModal2 = (myprops) => {
const [isModalOpen, { setTrue: showModal, setFalse: hideModal }] = useBoolean(false);
const [isPopup, setisPopup] = React.useState(true);
const titleId = useId('title');
React.useEffect(() => {
showModal();
}, [isPopup]);
function ExitHandler() {
hideModal();
setisPopup(current => !current)
myprops.handler();
}
return (
<div>
<Modal
titleAriaId={titleId}
isOpen={isModalOpen}
onDismiss={ExitHandler}
isBlocking={true}
containerClassName={contentStyles.container}
>
<div className={contentStyles.header}>
<span id={titleId}>Modal Popup</span>
<IconButton
styles={iconButtonStyles}
iconProps={cancelIcon}
ariaLabel="Close popup modal"
onClick={ExitHandler}
/>
</div>
<div className={contentStyles.body}>
<p dangerouslySetInnerHTML={{__html:myprops.OurValue}}>
</p>
</div>
</Modal>
</div>
);
};
const cancelIcon: IIconProps = { iconName: 'Cancel' };
const theme = getTheme();
const contentStyles = mergeStyleSets({
container: {
display: 'flex',
flexFlow: 'column nowrap',
alignItems: 'stretch',
},
header: [
// eslint-disable-next-line deprecation/deprecation
theme.fonts.xLarge,
{
flex: '1 1 auto',
borderTop: '4px solid ${theme.palette.themePrimary}',
color: theme.palette.neutralPrimary,
display: 'flex',
alignItems: 'center',
fontWeight: FontWeights.semibold,
padding: '12px 12px 14px 24px',
},
],
body: {
flex: '4 4 auto',
padding: '0 24px 24px 24px',
overflowY: 'hidden',
selectors: {
p: { margin: '14px 0' },
'p:first-child': { marginTop: 0 },
'p:last-child': { marginBottom: 0 },
},
},
});
const stackProps: Partial<IStackProps> = {
horizontal: true,
tokens: { childrenGap: 40 },
styles: { root: { marginBottom: 20 } },
};
const iconButtonStyles: Partial<IButtonStyles> = {
root: {
color: theme.palette.neutralPrimary,
marginLeft: 'auto',
marginTop: '4px',
marginRight: '2px',
},
rootHovered: {
color: theme.palette.neutralDark,
},
};
And to secure the dangerouslySetInnerHTML, i did the following steps:-
1- Inside my Node.Js CMD >> i run this command inside my project directory:-
npm install dompurify eslint-plugin-risxss
2- Then inside my above .tsx i made the following modifications:-
I added this import import { sanitize } from 'dompurify';
An I replaced this unsafe code <p dangerouslySetInnerHTML={{__html:myprops.OurValue}}></p> with this <div dangerouslySetInnerHTML={{ __html: sanitize(myprops.OurValue) }} />
So I have the following question:-
Now my approach (of using sanitize(myprops.OurValue) will/should securely render HTML as Rich-Text inside the popup since i am using the sanitize function which is part of the dompurify eslint-plugin-risxss. but i read another approach which mentioned that to securely render HTML as Rich-Text inside the popup, we can use the html-react-parser package as follow {parse(myprops.OurValue)}. So what are the differences between using 'html-react-parser' & using 'dompurify eslint-plugin-risxss' to securely render an HTML code as Rich-Text inside the React web part's popup?
Here is my Full web part code:-
inside the MyModalPopupWebPart.ts:-
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '#microsoft/sp-core-library';
import {
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '#microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '#microsoft/sp-webpart-base';
import * as strings from 'MyModalPopupWebPartStrings';
import MyModalPopup from './components/MyModalPopup';
import { IMyModalPopupProps } from './components/IMyModalPopupProps';
export interface IMyModalPopupWebPartProps {
description: string;
WhoWeAre: string;
OurValue:string;
}
export default class MyModalPopupWebPart extends BaseClientSideWebPart<IMyModalPopupWebPartProps> {
public render(): void {
const element: React.ReactElement<IMyModalPopupProps> = React.createElement(
MyModalPopup,
{
description: this.properties.description,
WhoWeAre: this.properties.WhoWeAre,
OurValue: this.properties.OurValue
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('WhoWeAre', {
label: "who We Are",
multiline: true
}),
PropertyPaneTextField('OurValue', {
label: "Our value"
}), PropertyPaneTextField('description', {
label: "Description",
multiline: true
}),
]
}
]
}
]
};
}
}
inside the MyModalPopup.tsx:-
import * as React from 'react';
import { IMyModalPopupProps } from './IMyModalPopupProps';
import { DefaultButton } from '#fluentui/react/lib/Button';
import { MYModal } from './MYModal';
import { MYModal2 } from './MYModal2';
interface IPopupState {
showModal: string;
}
export default class MyModalPopup extends React.Component<IMyModalPopupProps, IPopupState> {
constructor(props: IMyModalPopupProps, state: IPopupState) {
super(props);
this.state = {
showModal: ''
};
this.handler = this.handler.bind(this);
this.Buttonclick = this.Buttonclick.bind(this);
}
handler() {
this.setState({
showModal: ''
})
}
private Buttonclick(e, whichModal) {
e.preventDefault();
this.setState({ showModal: whichModal });
}
public render(): React.ReactElement<IMyModalPopupProps> {
const { showModal } = this.state;
return (
<div>
<DefaultButton onClick={(e) => this.Buttonclick(e, 'our-value')} text="Our Value" />
{ showModal === 'our-value' && <MYModal2 OurValue={this.props.OurValue} myprops={this.state} handler={this.handler} />}
<DefaultButton onClick={(e) => this.Buttonclick(e, 'who-we-are')} text="Who We Are" />
{ showModal === 'who-we-are' && <MYModal WhoWeAre={this.props.WhoWeAre} myprops={this.state} handler={this.handler} />}
</div>
);
}
}
Actually, html-react-parser returns ReactJs object, and its return type is like React.createElement or like type of called JSX.
Using DOMPurify.sanitize will return safe pure HTML elements which those are different to the object that html-react-parser returns. the risxss ESLint plugin will force you to use sanitizing with any kind of sanitize function or library, that I left an answer to your other question to how to Sanitize your string HTML.
Eventually, using sanitizing is better because is the html-react-parser will convert your string HTML to ReactJs object with some tiny changes that would be dangerous because it is possible to have some script of string HTML in the project and it maybe will be harmful it just remove the onclick or onload, etc, from HTML tags but sanitizing will remove all possible harmful tags. also sanitizing will receive configuration, which means you can have your own options for sanitizing.

How to capture a photo with expo-camera using vue native?

I am new to vue native and im trying to create a page on the app where i can use the camera and capture & show a photo using the expo-camera directive.
This is what i have done:
<template>
<view class="view-container">
<view class="container">
<text>Camera screen</text>
<camera class="container" :type="this.type" />
<touchable-opacity
class="camera-touchable-opacity"
:on-press="capturePic"
>
</view>
<view class="home-btn">
<button title="Go to home screen" #press="goToHomeScreen"></button>
</view>
</view>
</template>
<script>
import * as Permissions from 'expo-permissions';
import { Camera } from 'expo-camera';
export default {
props: {
navigation: { type: Object }
},
data: function() {
return {
hasCameraPermission: false,
type: Camera.Constants.Type.back,
};
},
mounted: function() {
Permissions.askAsync(Permissions.CAMERA)
.then(status => {
hasCameraPermission = status.status == "granted" ? true : false;
}).catch((err)=>{
console.log(err);
});
},
components: { Camera },
methods: {
goToHomeScreen() {
this.navigation.navigate("Home");
},
capturePic: async function() {
if(!camera) return
const photo = await camera.takePictureAsync();
}
}
}
</script>
i receive this warning:
[Unhandled promise rejection: ReferenceError: Can't find variable: camera]
I don't know what i need since i didn't find anything regarding capturing a photo in the docs.
You can refer your camera as this.$refs.camera in your method, since you need to have a reference on the element as ref="camera" in your code..
<camera class="container" :type="this.type" ref="camera"/>
The capture function will be this.$refs.camera.takePictureAsync()
In your code
capturePic: async function() {
if(!camera) return
const photo = await camera.takePictureAsync();
}

How to create an array of objects in React Native from seperate components?

I'm new to React Native, so I understand I have alot to learn.
I'm creating a custom class component here:
import React, { Component, useState } from 'react';
import {View,Text,StyleSheet,TextInput, Button} from 'react-native';
class Square extends React.Component{
constructor(pos,text,won,save){
this.state = {
pos : 0,
text : 'EDIT',
won : false,
save : false,
};
}
setPos = (pos) =>{
this.setState(pos)
}
getPos = () => {
return (this.pos);
}
setText=(text)=>{
this.setState(text)
}
getText=()=>{
return (this.text);
}
setWon=(won)=>{
this.setState(won)
}
getWon=()=>{
return (this.won);
}
setSave=(save)=>{
this.setState(save)
}
getSave=()=>{
return (this.save);
}
};
export default Square;
Then I want to create an array of those objects in a different component and display a piece of information from each object.
import {View, Text, StyleSheet, Button, Alert} from 'react-native';
import Square from '../components/Square';
const NewGameScreen = () => {
let arrSquare = [];
for (let i = 0; i < 25; i++){
arrSquare.push({
THIS IS WHERE I'M HAVING TROUBLE
});
}
console.log(arrSquare[0].getPos)
return(
<View style = {styles.screen}>
<View style = {styles.row}>
<Text>{arrSquare[0].getPos}</Text>
</View>
</View>
)
};
However from the above code I'm sure it's clear I'm missing something. I would have expected to use something like Square[i].setPos(i); but that throws errors. The console log also gives 'undefined' so that makes me think I haven't declared something or haven't declared it properly. Thanks in advance.
well the way I would go about this is to have a simple array of json object something like this:
let squareArr = [{
id: 0,
pos : 0,
text : 'EDIT',
won : false,
save : false,
},
{
id: 1,
pos : 0,
text : 'EDIT',
won : false,
save : false,
},
{
id: 2,
pos : 0,
text : 'EDIT',
won : false,
save : false,
}
]
then you can do the the read and the edit.
to display a position:
in your render method you can do this:
<View style = {styles.screen}>
<View style = {styles.row}>
squareArr.map((square) => <Text>{square.pos}</Text>)
</View>
</View>
to edit a position:
if you want to change a value in your JSON then just use the object index as a way to indicate which object you wanna change. For example want to change the pos of the second object then I would do this:
squareArr[1].pos = 3
I am not quite sure what is the whole project is to give you to give you the best solution but i hope this helps..
feel free to ask if you have any questions

Update child component props from Parent component react native

I want to update child component props from Parent component my senarios is I have one component which I am passing one array list which is come from API response so below is my code
<DateRangePicker
theme={{
calendarBackground: colors.white,
selectedDayBackgroundColor: colors.kellyGreen,
selectedDayTextColor: colors.white,
todayTextColor: colors.kellyGreen,
dayTextColor: colors.intrestedButton,
dotColor: colors.kellyGreen,
selectedDotColor: colors.kellyGreen,
arrowColor: colors.kellyGreen,
monthTextColor: colors.black,
textDayFontFamily: globals.SFProTextRegular,
textMonthFontFamily: globals.SFProTextMedium,
textDayHeaderFontFamily: globals.SFProTextMedium,
textMonthFontWeight: "bold",
textDayFontSize: globals.font_11,
textMonthFontSize: globals.font_16,
textDayHeaderFontSize: globals.font_13
}}
minDate={null}
isFrom={'golfActivity'}
monthFormat={globals.selectedLocal.DATE_MMMMyyyy}
initialRange={[this.state.fromDate, this.state.toDate]}
onSuccess={(s, e) => this.setState({ fromDate: e, toDate: s })}
theme={{ markColor: colors.kellyGreen, markTextColor: colors.white
}}
underLineValue = {this.state.underLineValue}
onVisibleMonthsChange={months => { this.getChangeMonth(months) }}
/>
in above code underLineValue is my array list which is come from API side and when I change month at that time i onVisibleMonthsChange props is called and I get newly updated month and year so again I am calling API for that and fill new my updated array refer my getChangeMonth method as below
getChangeMonth = (months) => {
countCall = countCall + 1
if (countCall === 1) {
this.setState({isMonthChange: true})
visibleMonth = months[months.length - 1].month;
visibleYear = months[months.length - 1].year;
globals.visibleMonth= visibleMonth;
globals.visibleYear= visibleYear;
console.log("on visible month", visibleMonth);
console.log("on visible year", visibleYear);
this.callCounterAPI(visibleMonth, visibleYear);
countCall = - 1
}
}
callCounterAPI(month, year){
this.setState({ underLineValue: []})
API.getCalendarCount(this.onResponseCalendarCount, month, year,true)
}
onResponseCalendarCount = {
success: (response) => {
this.setState({underLineValue: response.data })
},
error: (err) => {
console.log("onResponseCalendarCount error-->>", err);
},
complete: () => {
}
}
export default class DateRangePicker extends Component<Props> {
state = { isFromDatePicked: false, isToDatePicked: false, markedDates: {} }
componentDidMount() {
console.log("DateRangePicker-->"+ JSON.stringify(this.props));
}
}
onResponseCalendarCount callback I fill updated arraylist underLineValue but in DateRangePicker when i print it's props I did't get updated arraylist so any one have idea how can i solve this issue? Your all suggestions are welcome
You can use getDerivedStateFromProps method in child component like this:
import isEqual from 'lodash/isEqual'
static getDerivedStateFromProps(props, state) {
if (!isEqual(props.underLineValue, state.underLineValue)) {
return {
underLineValue: props.underLineValue
}
}
return null;
}
This will update your child component. Let me know if it's working.

Function call under onKeyPress in reactjs isn't getting called

In the below code when i enter a search string and press enter, this is becoming undefined and as a result the function is not getting called.Can anybody please help me understand why? I have tried almost everything but nothing seems to be working neither could i find any pointers to the problem i am facing.
class HomepageBody extends Component{
constructor(props){
super(props);
this.state = {
value :'',
error: null,
isLoaded: false,
array: [],
mobile: ''
}
this.readSearchString = this.readSearchString.bind(this);
this.doSomething = this.doSomething.bind(this);
}
readSearchString(event){
if(event.target.value === ''){
this.setState({
error: null,
array: ''
});
}
else{
this.setState ({
value : event.target.value
});
}
}
doSomething = () => {
fetch(`http://localhost:8080/items?search=${this.state.value}&page=1`,
{
headers: {
'Accept': 'application/json'
}
})
.then(res => res.json())
.then(
(result) => {
if(result.length != 0){
this.setState({
isLoaded: true,
array: result,
error: null
});
}
else{
this.setState({
isLoaded: true,
error : "No matches found",
array: ''
})
}
},
(error) => {
this.setState({
isLoaded: true,
error: "We are experiencing some temporary problem, please try again later"
});
}
)
}
render () {
const {mobile} = this.props;
return(
<Container>
<Header
as='h1'
content='Title'
style={{
fontSize: mobile ? '1.2em' : '3em',
fontWeight: 'normal',
marginBottom: 0,
marginTop: mobile ? '5em' : '3em',
display:'block'
}}
/>
<Input icon={<Icon name='search' inverted circular link />}
placeholder='Search .....'
style={{
fontSize: mobile ? '1em' : '1em',
fontWeight: 'normal',
marginTop: mobile ? '1em' : '1em',
width: mobile ? '280px' : '600px',
}}
onChange={ this.readSearchString }
onKeyPress={(event) => {
if(event.key === 'Enter'){
this.doSomething()
}
}}
focus
/>
</Container>
)
}
}
HomepageBody.propTypes = {
mobile: PropTypes.bool,
}
Thanks,
Vikram
Yes, thats what i had done. But it didn't work. However i figured out a solution. If i'm not using the semantic ui framework's component, then i can define the function inline for onKeyPress and it works without any problems, but when i use the semantic ui framework and use the <Input> component, i have to override the function call. So this is how i did it
<Input>
..........
.........
onKeyPress = {this.onKeyPress}
</Input>
onKeyPress= (e) => {
if(e.key === 'Enter')
this.doSomething();
}
So i presume its got to something to do with semantic ui and the way it handles events within the component.
Set an attribute of tabIndex="0" and it will work.
tabindex="0" allows elements besides links and form elements to
receive keyboard focus. It does not change the tab order, but places
the element in the logical navigation flow, as if it were a link on
the page.

Categories