Why is only the last component in array animating? - reactjs

Goal: create an OptionFan button that when pressed, rotates on its Z axis, and FanItems release from behind the main button and travel along their own respective vectors.
OptionFan.js:
import React, { useState, useEffect } from 'react';
import { Image, View, Animated, StyleSheet, TouchableOpacity, Dimensions } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
import FanItem from './FanItem';
const { height, width } = Dimensions.get('window');
export default class OptionFan extends React.Component {
constructor (props) {
super(props);
this.state = {
animatedRotate: new Animated.Value(0),
expanded: false
};
}
handlePress = () => {
if (this.state.expanded) {
// button is opened
Animated.spring(this.state.animatedRotate, {
toValue: 0
}).start();
this.refs.option.collapse();
this.setState({ expanded: !this.state.expanded });
} else {
// button is collapsed
Animated.spring(this.state.animatedRotate, {
toValue: 1
}).start();
this.refs.option.expand();
this.setState({ expanded: !this.state.expanded });
}
};
render () {
const animatedRotation = this.state.animatedRotate.interpolate({
inputRange: [ 0, 0.5, 1 ],
outputRange: [ '0deg', '90deg', '180deg' ]
});
return (
<View>
<View style={{ position: 'absolute', left: 2, top: 2 }}>
{this.props.options.map((item, index) => (
<FanItem ref={'option'} icon={item.icon} onPress={item.onPress} index={index} />
))}
</View>
<TouchableOpacity style={styles.container} onPress={() => this.handlePress()}>
<Animated.Image
resizeMode={'contain'}
source={require('./src/assets/img/arrow-up.png')}
style={{ transform: [ { rotateZ: animatedRotation } ], ...styles.icon }}
/>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
borderRadius: 30,
backgroundColor: '#E06363',
elevation: 15,
shadowOffset: {
height: 3,
width: 3
},
shadowColor: '#333',
shadowOpacity: 0.5,
shadowRadius: 5,
height: width * 0.155,
width: width * 0.155
},
icon: {
height: width * 0.06,
width: width * 0.06
},
optContainer: {
justifyContent: 'center',
alignItems: 'center',
borderRadius: 30,
backgroundColor: '#219F75',
elevation: 5,
shadowOffset: {
height: 3,
width: 3
},
shadowColor: '#333',
shadowOpacity: 0.5,
shadowRadius: 5,
height: width * 0.13,
width: width * 0.13,
position: 'absolute'
}
});
FanItem.js:
import React, { useState } from 'react';
import { Image, Animated, StyleSheet, TouchableOpacity, Dimensions } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
const { width } = Dimensions.get('window');
export default class FanItem extends React.Component {
constructor (props) {
super(props);
this.state = {
animatedOffset: new Animated.ValueXY(0),
animatedOpacity: new Animated.Value(0)
};
}
expand () {
let offset = { x: 0, y: 0 };
switch (this.props.index) {
case 0:
offset = { x: -50, y: 20 };
break;
case 1:
offset = { x: -20, y: 50 };
break;
case 2:
offset = { x: 20, y: 50 };
break;
case 3:
offset = { x: 75, y: -20 };
break;
}
Animated.parallel([
Animated.spring(this.state.animatedOffset, { toValue: offset }),
Animated.timing(this.state.animatedOpacity, { toValue: 1, duration: 600 })
]).start();
}
collapse () {
Animated.parallel([
Animated.spring(this.state.animatedOffset, { toValue: 0 }),
Animated.timing(this.state.animatedOpacity, { toValue: 0, duration: 600 })
]).start();
}
render () {
return (
<Animated.View
style={
(this.props.style,
{
left: this.state.animatedOffset.x,
top: this.state.animatedOffset.y,
opacity: this.state.animatedOpacity
})
}
>
<TouchableOpacity style={styles.container} onPress={this.props.onPress}>
<Image resizeMode={'contain'} source={this.props.icon} style={styles.icon} />
</TouchableOpacity>
</Animated.View>
);
}
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
borderRadius: 30,
backgroundColor: '#219F75',
elevation: 5,
shadowOffset: {
height: 3,
width: 3
},
shadowColor: '#333',
shadowOpacity: 0.5,
shadowRadius: 5,
height: width * 0.13,
width: width * 0.13,
position: 'absolute'
},
icon: {
height: width * 0.08,
width: width * 0.08
}
});
Implementation:
import React from 'react';
import { StyleSheet, View, Dimensions } from 'react-native';
import Component from './Component';
const { height, width } = Dimensions.get('window');
const testArr = [
{
icon: require('./src/assets/img/chat.png'),
onPress: () => alert('start chat')
},
{
icon: require('./src/assets/img/white_video.png'),
onPress: () => alert('video chat')
},
{
icon: require('./src/assets/img/white_voice.png'),
onPress: () => alert('voice chat')
},
{
icon: require('./src/assets/img/camera.png'),
onPress: () => alert('request selfie')
}
];
const App = () => {
return (
<View style={styles.screen}>
<Component options={testArr} />
</View>
);
};
const styles = StyleSheet.create({
screen: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#E6E6E6'
}
});
export default App;
Problem: The issue is, only the last FanItem item runs its animation. (opacity, and vector translation). before implementing the opacity animation I could tell the first three FanItems did in fact render behind the main button, because I could see them when pressing the main button, as the opacity temporarily changes for the duration of the button click.
My question is 1) why are the first three mapped items not animating? and 2) how to resolve this?

You are storing ref of FanItem in option. but, ref gets overridden in each iteration of map. so, at the end it only stores ref of last FanItem in option. So, first declare one array in constructor to store ref of each FanItem:
constructor(props) {
super(props);
// your other code
this.refOptions = [];
}
Store ref of each FanItem separately like this:
{this.props.options.map((item, index) => (
<FanItem ref={(ref) => this.refOptions[index] = ref} icon={item.icon} onPress={item.onPress} index={index} />
))}
and then to animate each FanItem:
for(var i = 0; i < this.refOptions.length; i++){
this.refOptions[i].expand(); //call 'expand' or 'collapse' as required
}
This is expo snack link for your reference:
https://snack.expo.io/BygobuL3JL

Related

Can not seem to add 2 different animations to Animated.Image in react native

I have a bit of code that displays an image and when the image is clicked, it spins round to the right and if clicked again it spins round to the left. All is working but I have added another animation. I am not getting any errors but it does not seem to be doing anything?
What I am aiming for is when it is clicked on it bounces in and out as well as spinning.
All the code is there that sort of works. I am not asking anyone to do this and say I have not tried anything but I have tried so many different things and this way is the only way I am not getting errors. The new animation is called animate and I have added it to the function.
Any help would be greatly appreciated.
All the code:
import React, { useRef, useState, useCallback } from 'react';
import {
View,
StyleSheet,
Animated,
Image,
TouchableOpacity,
Easing,
TouchableWithoutFeedback,
} from 'react-native';
import Constants from 'expo-constants';
const TabIcon = ({ onPress, menuToggled }) => {
const logoStyles = [styles.logoStyle];
const animation = useRef(new Animated.Value(menuToggled ? 0 : 1)).current;
const startAnimation = () => {
Animated.timing(animation, {
toValue: menuToggled ? 1 :0,
duration: 5500,
friction:2,
tension:10,
easing: Easing.in(Easing.bounce),
useNativeDriver: true,
}).start();
};
const rotateInterpolate = animation.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg'],
});
const animatedStyles = { transform: [{ rotate: rotateInterpolate }] };
logoStyles.push(animatedStyles);
return (
<TouchableWithoutFeedback
onPress={() => {
startAnimation();
onPress?.();
}}>
<Animated.View style={animatedStyles}>
<Animated.Image
style={styles.tinyLogo}
source={{
uri: 'https://reactnative.dev/img/tiny_logo.png',
}}
/>
</Animated.View>
</TouchableWithoutFeedback>
);
};
const App = () => {
const spinValue = useRef(new Animated.Value(0)).current;
const [menuToggled, setMenuToggled] = useState(null);
let opacity = new Animated.Value(0);
const animate = () => {
opacity.setValue(0);
Animated.timing(opacity, {
toValue: 1,
duration: 1200,
easing: Easing.bounce,
useNativeDriver: true,
}).start();
};
const size = opacity.interpolate({
inputRange: [0, 1],
outputRange: [0, 80],
});
const animatedStyles = [
{
opacity,
width: size,
height: size,
},
];
return (
<View style={styles.container}>
<TabIcon
onPress={() => setMenuToggled((prev) => !prev)}
menuToggled={menuToggled}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
},
tinyLogo: {
width: 150,
height: 150,
borderRadius: 100,
margin: 28,
},
});
export default App;

card flip animation flip and then content flickers to visible in Android

I have a card flip animation on my application. The card functions as a timer. The content should be visible straight away but there is a flicker when render contents.
I use React-native-reanimated v2.0.1(ya, it's so outdated..)
Does anyone know why the number inside the card flickers?
Here is my code.
import React, { useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import Animated from 'react-native-reanimated';
import type FlipCardProps from './FlipCardProps';
const styles = StyleSheet.create({
container: {
height: 32,
width: 24,
},
animatedCard: {
alignItems: 'center',
backfaceVisibility: 'hidden',
justifyContent: 'center',
position: 'absolute',
},
});
const PERSPECTIVE = 100;
const Z_INDEX_CHANGE_ANGLE = 90;
export default function FlipCard(props: FlipCardProps) {
const {
backCard,
frontCard,
reanimationKey,
style,
} = props;
const sharedAngle = Animated.useSharedValue(0);
const animatedFrontCardStyle = Animated.useAnimatedStyle(() => {
return {
zIndex: sharedAngle.value < Z_INDEX_CHANGE_ANGLE ? 2 : 1,
transform: [
{ perspective: PERSPECTIVE },
{ rotateX: `${sharedAngle.value}deg` },
],
};
});
const animatedBackCardStyle = Animated.useAnimatedStyle(() => {
return {
zIndex: sharedAngle.value <= Z_INDEX_CHANGE_ANGLE ? 1 : 2,
transform: [
{ perspective: PERSPECTIVE },
{ rotateX: `${(sharedAngle.value + 180)}deg` },
],
};
});
useEffect(() => {
sharedAngle.value = 0;
sharedAngle.value = Animated.withTiming(180, { duration: 500 });
}, [reanimationKey]);
return (
<View style={[styles.container, style]}>
<Animated.View style={[styles.animatedCard, animatedFrontCardStyle]}>
{frontCard}
</Animated.View>
<Animated.View style={[styles.animatedCard, animatedBackCardStyle]}>
{backCard}
</Animated.View>
</View>
);
};

add additional style if iPhoneX

I have a helper function is.iphone('x') to check for iphone x and I want some styles to get added to the styles.icon and styles.textContainer and styles.container if true. This needs to happen inside the render method. However, when I try to run my code:
const styles = {
addToCartButton: {
borderRadius: 0,
width: windowWidth,
},
container: {
overflow: 'hidden',
},
innerContainer: {
width: 2 * windowWidth,
flexDirection: 'row',
},
checkoutButton: {
borderRadius: 0,
width: windowWidth,
},
icon: {
backgroundColor: accentColor,
},
textContainer: {},
}
export class CartButton extends Component {
checkoutButtonColor = new Animated.Value(3)
xOffset = new Animated.Value(-windowWidth)
dynamicStyles = {
transform: [ { translateX: this.xOffset } ],
}
checkoutDynamicStyles = {
backgroundColor: this.checkoutButtonColor.interpolate({
inputRange: [ 0, 3 ],
outputRange: [ color('b'), accentColor ],
}),
}
animate = () => {
Animated.sequence([
Animated.timing(this.xOffset, {
toValue: 0,
duration: 500,
useNativeDriver: true,
}),
Animated.timing(this.checkoutButtonColor, {
toValue: 0,
duration: 250,
userNativeDriver: true,
}),
]).start()
}
)
}
render () {
if (is.iphone('x')) {
styles.icon.paddingBottom = spacing
styles.textContainer.paddingBottom = spacing
styles.container.marginBottom = spacingSizes.large
}
return (
<View style={styles.container}>
<Animated.View style={[ styles.innerContainer, this.dynamicStyles ]}>
{this.renderCheckout()}
{this.renderAddToCart()}
</Animated.View>
</View>
)
}
}
I get the error "you are attempting to set Key 'paddingBottom' with value '14' (spacing =14) on an object that is meant to be immutable and has been frozen. How to do this any suggestions?
Update your code and replace style={styles.container} by style={[styles.container, is.iphone('x') ? { marginBottom: spacing } : {}]} and do the same where you use the icon style.

React Native: How to animate a particular component?

I am making a quiz. And all options will render in for loop.
Expected Behaviour:
When I click on an option, if it is the wrong answer then it should change the background color to red and it should shake.
Below is the code I am trying.
import React, { Component } from "react";
import {
View,
Text,
TouchableWithoutFeedback,
Animated,
Easing
} from "react-native";
class MCQOptions extends Component {
state = {
optionSelectedStatus: 0 // 0: unselected, 1: correct, -1: wrong
};
constructor() {
super();
this.animatedValue = new Animated.Value(0);
this.shakeAnimValue = new Animated.Value(0);
}
onOptionSelected(i) {
// this.props.showNextQuestion();
var answer = this.props.answer;
if (answer == i) {
this.setState({ optionSelectedStatus: 1 });
this.showCorrectAnimation();
} else {
this.setState({ optionSelectedStatus: -1 });
this.showErrorAnimation();
}
}
showErrorAnimation() {
this.shakeAnimValue.setValue(0);
Animated.timing(this.shakeAnimValue, {
toValue: 1,
duration: 300,
easing: Easing.linear
}).start();
}
showCorrectAnimation() {}
getOptions() {
var options = [];
var optionSelectedStyle = styles.optionUnselected;
var optionShadowStyle = styles.optionShadow;
if (this.state.optionSelectedStatus == 1) {
optionSelectedStyle = styles.optionCorrect;
optionShadowStyle = null;
} else if (this.state.optionSelectedStatus == -1) {
optionSelectedStyle = styles.optionWrong;
optionShadowStyle = null;
}
const marginLeft = this.shakeAnimValue.interpolate({
inputRange: [0, 0.2, 0.4, 0.6, 0.8, 0.9, 1],
outputRange: [0, -10, 10, -10, 10, -10, 0]
});
for (var i = 0; i < this.props.options.length; i++) {
options.push(
<TouchableWithoutFeedback
onPress={this.onOptionSelected.bind(this, this.props.indexes[i])}
key={"options_" + i}
>
<View style={styles.optionBox}>
<View style={optionShadowStyle} />
<Animated.Text
style={[
styles.option,
optionSelectedStyle,
{ marginLeft: marginLeft }
]}
key={"option" + i}
>
{this.props.options[i]}
</Animated.Text>
</View>
</TouchableWithoutFeedback>
);
}
return options;
}
render() {
const marginTop = this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [100, 0]
});
const opacity = this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, 1]
});
return (
<Animated.View style={{ marginTop: marginTop, opacity: opacity }}>
{this.getOptions()}
</Animated.View>
);
}
// Animations
componentDidMount() {
this.slideUpOptionsContainer();
}
componentWillReceiveProps() {
this.slideUpOptionsContainer();
this.setState({ optionSelectedStatus: 0 });
}
slideUpOptionsContainer() {
this.animatedValue.setValue(0);
Animated.timing(this.animatedValue, {
toValue: 1,
duration: 300,
easing: Easing.linear
}).start();
}
}
const styles = {
optionBox: {
margin: 5
},
optionsContainer: {
marginTop: 100
},
option: {
padding: 10,
textAlign: "center",
borderRadius: 10,
overflow: "hidden",
width: "100%"
},
optionUnselected: {
backgroundColor: "#FFF"
},
optionWrong: {
backgroundColor: "red"
},
optionCorrect: {
backgroundColor: "green"
},
optionShadow: {
backgroundColor: "rgba(255,255,255,0.85)",
position: "absolute",
width: "100%",
height: "100%",
left: -5,
top: 5,
borderRadius: 10
}
};
export default MCQOptions;
The above code animating(shake) all the options (Which is proper according to the login written), and I am stuck how to make only the clicked option get animated instead all?
Edited:
Parent component with props feed:
class MCQ extends Component<{}> {
render() {
var options = ["yes", "no", "can't define"];
var indexes = [1,2,3];
var answer = 1;
optionsObj = <MCQOptions
options={options}
indexes={indexes}
answer={answer}/>;
return (
<View style={styles.container} >
<View style={styles.optionsContainer}>
{optionsObj}
</View>
</View>
);
}
}
const styles = {
container: {
flex: 1,
backgroundColor: "blue",
paddingTop: 20,
justifyContent: 'flex-start',
padding: 20
},
};
export default MCQ;
Second EDIT:
Trying to simplify problem.
Below is the simplified code with zero props. I want to animate clicked element only.
import React, { Component } from "react";
import {
View,
Text,
TouchableWithoutFeedback,
Animated,
Easing
} from "react-native";
class MCQOptions extends Component {
constructor() {
super();
this.shakeAnimValue = new Animated.Value(0);
}
showErrorAnimation() {
this.shakeAnimValue.setValue(0);
Animated.timing(this.shakeAnimValue, {
toValue: 1,
duration: 300,
easing: Easing.linear
}).start();
}
getOptions() {
const marginLeft = this.shakeAnimValue.interpolate({
inputRange: [0, 0.2, 0.4, 0.6, 0.8, 0.9, 1],
outputRange: [0, -10, 10, -10, 10, -10, 0]
});
var options = [];
for (var i = 0; i < 4; i++) {
options.push(
<TouchableWithoutFeedback
onPress={this.showErrorAnimation.bind(this)}
key={"options_" + i}
>
<View style={styles.optionBox}>
<Animated.Text style={[
styles.option,
{ marginLeft: marginLeft }
]}
key={"option" + i}
>
{"Option "+i}
</Animated.Text>
</View>
</TouchableWithoutFeedback>
);
}
return options;
}
render() {
return (
<View style={{ marginTop: 100}}>
{this.getOptions()}
</View>
);
}
}
const styles = {
optionBox: {
margin: 5
},
optionsContainer: {
marginTop: 100
},
option: {
padding: 10,
textAlign: "center",
borderRadius: 10,
overflow: "hidden",
width: "100%"
},
optionUnselected: {
backgroundColor: "#FFF"
},
optionWrong: {
backgroundColor: "red"
},
};
export default MCQOptions;
Since you want to animate them separately, they cannot bind to the same Animated object. You have to make them multiple, for example:
Example:
export class App extends Component {
constructor() {
super();
this.getOptions = this.getOptions.bind(this);
this.originalOptions = [0,1,2,3];
this.shakeAnimations = this.originalOptions.map( (i) => new Animated.Value(0) );
}
showErrorAnimation(i) {
this.shakeAnimations[i].setValue(0);
Animated.timing(this.shakeAnimations[i], {
toValue: 1,
duration: 300,
easing: Easing.linear
}).start();
}
getOptions() {
var options = this.originalOptions.map( (i) => {
const marginLeft = this.shakeAnimations[i].interpolate({
inputRange: [0, 0.2, 0.4, 0.6, 0.8, 0.9, 1],
outputRange: [0, -10, 10, -10, 10, -10, 0]
});
return (
<TouchableWithoutFeedback
onPress={() => this.showErrorAnimation(i)}
key={"options_" + i}
>
<View style={styles.optionBox}>
<Animated.Text style={[
styles.option,
{ marginLeft: marginLeft }
]}
key={"option" + i}
>
{"Option "+i}
</Animated.Text>
</View>
</TouchableWithoutFeedback>
)
});
return options;
}
render() {
return (
<View style={{ marginTop: 100}}>
{this.getOptions()}
</View>
);
}
}
const styles = {
optionBox: {
margin: 5
},
optionsContainer: {
marginTop: 100
},
option: {
padding: 10,
textAlign: "center",
borderRadius: 10,
overflow: "hidden",
width: "100%"
},
optionUnselected: {
backgroundColor: "#FFF"
},
optionWrong: {
backgroundColor: "red"
},
};
Result:

Proper way of using WebSockets with React Native

I'm new to React Native, but very familiar with React. As a beginner I'm looking to setup a connection between a cloud server and react-native with websockets as I've seen in the documentation. Unfortunately, there's no decent example out there that could help me out. This is all that I've got so far:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button
} from 'react-native';
export default class raspberry extends Component {
constructor(props) {
super(props);
this.state = { open: false };
this.socket = new WebSocket('ws://127.0.0.1:3000');
this.emit = this.emit.bind(this);
}
emit() {
this.setState(prevState => ({ open: !prevState.open }))
this.socket.send("It worked!")
}
render() {
const LED = {
backgroundColor: this.state.open ? 'lightgreen' : 'red',
height: 30,
position: 'absolute',
flexDirection: 'row',
bottom: 0,
width: 100,
height: 100,
top: 120,
borderRadius: 40,
justifyContent: 'space-between'
}
return (
<View style={styles.container}>
<Button
onPress={this.emit}
title={this.state.open ? "Turn off" : "Turn on"}
color="#21ba45"
accessibilityLabel="Learn more about this purple button"
/>
<View style={LED}></View>
</View>
);
}
componentDidMount() {
this.socket.onopen = () => socket.send(JSON.stringify({ type: 'greet', payload: 'Hello Mr. Server!' }))
this.socket.onmessage = ({ data }) => console.log(JSON.parse(data).payload)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('raspberry', () => raspberry);
Everything works fine, but when I press the button to send a message, this is the error I get:
Cannot send a message. Unknown WebSocket id 1
I also made a test with a js client and everything worked smooth..looking to see how I could get this fixed or some example sources where I can figure it out.
change the code
socket.send(JSON.stringify({ type: 'greet', payload: 'Hello Mr. Server!' }))
to
this.socket.send(JSON.stringify({ type: 'greet', payload: 'Hello Mr. Server!' }))
it should work.
here is my code to test, based on your code and RN 0.45 (and project generated by create-react-native-app), connects to a public websocket server wss://echo.websocket.org/, on my android it works fine and I can see the websocket server's echo message after I push the button.
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Button
} from 'react-native';
export default class App extends React.Component {
constructor() {
super();
this.state = {
open: false
};
this.socket = new WebSocket('wss://echo.websocket.org/');
this.emit = this.emit.bind(this);
}
emit() {
this.setState(prevState => ({
open: !prevState.open
}))
this.socket.send("It worked!")
}
componentDidMount() {
this.socket.onopen = () => this.socket.send(JSON.stringify({type: 'greet', payload: 'Hello Mr. Server!'}));
this.socket.onmessage = ({data}) => console.log(data);
}
render() {
const LED = {
backgroundColor: this.state.open
? 'lightgreen'
: 'red',
height: 30,
position: 'absolute',
flexDirection: 'row',
bottom: 0,
width: 100,
height: 100,
top: 120,
borderRadius: 40,
justifyContent: 'space-between'
}
return (
<View style={styles.container}>
<Button onPress={this.emit} title={this.state.open
? "Turn off"
: "Turn on"} color="#21ba45" accessibilityLabel="Learn more about this purple button"/>
<View style={LED}></View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5
}
});
According to documentation you need to add state connected to your component. And send anything only if connected state is true.
export default class raspberry extends Component {
constructor(props) {
super(props);
this.state = {
open: false,
connected: false
};
this.socket = new WebSocket('ws://127.0.0.1:3000');
this.socket.onopen = () => {
this.setState({connected:true})
};
this.emit = this.emit.bind(this);
}
emit() {
if( this.state.connected ) {
this.socket.send("It worked!")
this.setState(prevState => ({ open: !prevState.open }))
}
}
}
After I've done some researches I found that the WebSocket should be
new WebSocket("ws://10.0.2.2:PORT/")
where 10.0.2.2 means the localhost

Resources