im trying to use async function to consume my api, but it simply doesent work, it didnt even console log anything, here is my code:
import React, { Component } from 'react';
import { View, Text, StyleSheet, Dimensions } from 'react-native';
import { ScrollView } from 'react-native-gesture-handler';
import {NavigationContainer} from '#react-navigation/native'
import { SafeAreaView } from 'react-navigation';
import Profile from './Profile'
import api from '../services/api';
//import Home from './Mainpage'
const {heigth, width} = Dimensions.get('window')
here is just styles
styles = StyleSheet.create({
Container:{
flex:1,
justifyContent:"flex-end",
alignItems: "flex-end",
},
PlaceContainer:{
width: '100%',
maxHeight:200,
},
button:{
width:"10px",
height:"10px"
},
title:{
fontWeight:'bold',
fontSize: 20
},
place:{
width:width -40 ,
padding:20,
maxHeight:200,
marginHorizontal: 20,
marginVertical: 8,
backgroundColor: '#0ff'
},
separator:{
flex: 1,
height: StyleSheet.hairlineWidth,
backgroundColor: '#8E8E8E',
}
})
here I created a class to make everything
export default class Dermatologistas extends Component{
state ={
MessageError: null,
users: []
}
that is not working, it isnt even console logging
getUserList = async () => {
try {
const response = await api.get('/auth/list');
const { users } = response.data;
this.setState({ users });
} catch (response) {
this.setState({ errorMessage: response.data.error });
}
};
just rendered to test
render(){
const users = this.state.users
in this console.log it return Array []
console.log(users)
return(
<View>
{this.state.users.map(user => (
<View key={user._id} style={{marginTop: 15}}>
<Text>{user.title}</Text>
<Text>{user.speciality}</Text>
</View>
))}
</View>
)
}
}
Where's the call to getUserList?
Also, to your get method you should include the promise method then() which followed by a catch() method.
To summarize, your call should look like that:
fetch(url)
.then(function() {
})
.catch(function() {
});
Related
I have made entries in my mongodb database using node now I'm trying to fetch that data from backend to react front-end the 3rd party app used for cross-platform in node are cors and for react is axios(in script I have added "proxy":"http://localhost:5000"(5000 is my backend port)
Here is my code for NovelCard.js
import React, { Component } from 'react';
import { Container } from 'react-bootstrap';
import Card from 'react-bootstrap/Card';
import axios from 'axios';
const createSet = (post) => {
<Card style={{ width: '18rem' }}>
<Card.Img variant="top" src="holder.js/100px180" />
<Card.Body>
<Card.Title>{post.name}</Card.Title>
<Card.Subtitle className="mb-2 text-muted">{post.author}</Card.Subtitle>
<Card.Text>{post.synopsis}</Card.Text>
</Card.Body>
</Card>;
};
class Latest extends Component {
state = {
name: '',
author: '',
synopsis: '',
post: [],
};
componentDidMount = () => {
this.getData();
};
getData = () => {
axios
.get('http://localhost:5000/novels/')
.then((res) => {
const data = res.data;
this.setState({ post: data });
console.log('data recived');
})
.catch(() => {
alert('error');
});
};
render() {
console.log('state', this.state);
return <Container>{post.map(createSet)}</Container>;
}
}
export default Latest;
I'm getting error saying ***
src\components\home\Latest\NovelCard.js Line 45:24: 'post' is not
defined no-undef
Your post variable is available within you state. You need to do something like this within your render function.
render() {
console.log('state', this.state);
return <Container>{this.state.post.map(createSet)}</Container>;
}
Or you can do like this as well.
render() {
const { post } = this.state;
console.log('state', this.state);
return <Container>{post.map(createSet)}</Container>;
}
So I added a calendar to react which changes the workout data to a specific date. When I change the date the data does change correctly. If I refresh the react web pages I get the updated data. I'm just a little confused on how to have node js initiate the data update in react. After changing the data I have node emitting to this socket...
import { format } from 'date-fns'
import ScrapeExperienceLevel from './ScrapeExperienceLevel'
export default (websockets, queue, timer, workouts, scrapeExperienceLevel) => {
websockets.on('connection', socket => {
socket.on('joinRoom', roomName => {
socket.join(roomName)
})
socket.on('leaveRoom', roomName => {
socket.leave(roomName)
})
setInterval(function(){
socket.emit('GetCheckedInMemebers', queue.dump());
}, 3000);
socket.on('initScreen', screen => {
const screenWorkouts = workouts.current.filter(workout => workout.station == screen)
socket.emit('screenInfo', screenWorkouts)
socket.emit('queueInfo', queue.screen(screen - 1))
socket.emit('timer', { time: timer.formatTime().formattedTime })
})
// code in question
socket.on('GetWorkoutDate', async function (date) {
await workouts.getNewWorkouts(date.date)
const screenWorkouts = workouts.current.filter(workout => workout.station == 1)
socket.emit('UpdateWorkouts', screenWorkouts)
})
socket.on('initAdmin', () => {
socket.emit('queue', queue.dump())
socket.emit('timer', { time: timer.formatTime().formattedTime })
})
socket.on('initOverview', () => {
socket.emit('workouts', workouts.current)
socket.emit('queue', queue.dump())
socket.emit('timer', { time: timer.formatTime().formattedTime })
})
socket.on('addUser', async (person) => {
if(typeof person.member_id == 'undefined')
person.member_id = ''
else{
person.experiencelevel = await scrapeExperienceLevel.getExperienceLevel(person.member_id)
person.firstname = person.firstname + ' '
}
queue.add(person, timer)
websockets.emit('queue', queue.dump())
})
socket.on('removeUser', ({ group, person, list }) => {
queue.remove(group, person, list)
websockets.emit('queue', queue.dump())
})
socket.on('reorder', waiting => {
queue.reorder(waiting)
websockets.emit('queue', queue.dump())
})
socket.on('toggleTimer', () => {
if (timer.isRunning()) {
timer.pause()
} else {
timer.start()
}
})
})
}
Here's my Screen page's react...
import React, { Component } from 'react'
import { defaultTo } from 'ramda'
import './styles.css'
class Screen extends Component {
state = {
time: '',
rest: false,
workout: [],
queue: [],
}
UpdateTimer = ({ time, rest }) => {
this.setState({ time, rest })
}
UpdateScreenInfo = ({ data }) => {
this.setState({ workout: defaultTo({}, data[0]) })
}
UpdateQueueInfo = ({ data }) => {
this.setState({ queue: defaultTo({}, data) })
}
UpdateQueue = ({ queue, screenNumber }) => {
this.setState({ queue: defaultTo({}, queue[screenNumber - 1]) })
}
componentDidMount() {
const screenNumber = this.props.match.params.id
const { socket } = this.props
socket.on('connect', () => {
socket.emit('joinRoom', 'screens')
socket.emit('initScreen', screenNumber)
})
socket.on('timer', ({ time, rest }) => this.UpdateTimer({ time, rest }))
socket.on('screenInfo', data => this.UpdateScreenInfo({ data }))
socket.on('queueInfo', data => this.UpdateQueueInfo({ data }))
socket.on('queue', ({ queue }) => this.UpdateQueue({ queue, screenNumber }))
//socket.on('UpdateWorkouts', (updatedData) => this.UpdateWorkoutsData(updatedData))
}
componentWillUnmount() {
const { socket } = this.props
socket.off('timer', this.UpdateTimer)
socket.off('screenInfo', this.UpdateScreenInfo)
socket.off('queueInfo', this.UpdateQueueInfo)
socket.off('queue', this.UpdateQueue)
}
renderMovement = (movement, equipment) => {
if (!movement) return <noscript />
return (
<div className="screenMove">
{equipment && `${equipment.title} `}
{movement.title}
</div>
)
}
render() {
const { time, rest, queue } = this.state
const { workout } = this.props
const variation = defaultTo({}, workout.variation)
const person1 = defaultTo({}, queue[0])
const person2 = defaultTo({}, queue[1])
return (
<main className="screenWrapper">
<div className="screenHeader">
<span className="screenFirstUser">
{(() => {
if (person1.experiencelevel === 'novice') {
// light purple
return (
<div style={{color:'#BF5FFF', fontWeight: 'bold', display: 'inline-block'}}>{person1.firstname}</div>
)
} else if (person1.experiencelevel === 'beginner') {
// light blue
return (
<div style={{color:'#87CEFA', fontWeight: 'bold', display: 'inline-block'}}>{person1.firstname}</div>
)
} else if (person1.experiencelevel === 'intermediate') {
return (
<div style={{color:'orange', fontWeight: 'bold', display: 'inline-block'}}>{person1.firstname}</div>
)
} else if (person1.experiencelevel === 'advanced') {
// gym green
return (
<div style={{color:'#93C90E', fontWeight: 'bold', display: 'inline-block'}}>{person1.firstname}</div>
)
}else if (person1.experiencelevel === 'expert') {
return (
<div style={{color:'red', fontWeight: 'bold', display: 'inline-block'}}>{person1.firstname}</div>
)
}
})()}
</span>
<span className={`screenTimer alt ${rest ? 'rest' : ''}`}>{time ? time : '0:00'}</span>
<span className="screenSecondUser">
{(() => {
if (person2.experiencelevel === 'novice') {
// light purple
return (
<div style={{color:'#BF5FFF', fontWeight: 'bold', display: 'inline-block'}}>{person2.firstname}</div>
)
} else if (person2.experiencelevel === 'beginner') {
// light blue
return (
<div style={{color:'#87CEFA', fontWeight: 'bold', display: 'inline-block'}}>{person2.firstname}</div>
)
} else if (person2.experiencelevel === 'intermediate') {
return (
<div style={{color:'orange', fontWeight: 'bold', display: 'inline-block'}}>{person2.firstname}</div>
)
} else if (person2.experiencelevel === 'advanced') {
// gym green
return (
<div style={{color:'#93C90E', fontWeight: 'bold', display: 'inline-block'}}>{person2.firstname}</div>
)
}else if (person2.experiencelevel === 'expert') {
return (
<div style={{color:'red', fontWeight: 'bold', display: 'inline-block'}}>{person2.firstname}</div>
)
}
})()}
</span>
</div>
<p className="screenVariation">{variation.title}</p>
<div className="screenMoves">
{this.renderMovement(workout.movementOne, workout.equipmentOne)}
{this.renderMovement(workout.movementTwo, workout.equipmentTwo)}
{this.renderMovement(workout.movementThree, workout.equipmentThree)}
</div>
</main>
)
}
}
export default Screen
Also found the parent component Daniele enlightened me about. Now I'm sharing 1 socket connection throughout all the components.
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { path } from 'ramda'
import { connect, Provider } from 'react-redux'
import ReactDOM from 'react-dom'
import { BrowserRouter, Route, Redirect, Switch } from 'react-router-dom'
import openSocket from 'socket.io-client'
import { defaultTo } from 'ramda'
import './index.css'
import 'semantic-ui-css/semantic.min.css'
import store from './redux/store'
import Admin from './screens/Admin'
import Screens from './screens/Screens'
import Auth from './screens/Auth'
import BackScreen from './screens/Screens/Back'
import FrontScreen from './screens/Screens/Front'
const socket = openSocket(`http://${window.location.hostname}:${process.env.REACT_APP_WEBSOCKET_PORT}`)
function mapState(state) {
return {
loggedIn: path(['conf', 'loggedIn'], state),
}
}
class App extends Component {
state = {
workout: []
}
static propTypes = {
loggedIn: PropTypes.bool,
}
componentDidMount() {
socket.on('UpdateWorkouts', (workout) => { console.log(workout[0]); this.setState({ workout: defaultTo({}, workout[0]) }) })
}
render() {
const { loggedIn } = this.props
const workout = this.state
return (
<BrowserRouter>
<Switch>
{!loggedIn && <Route path="/" component={(props) => <Auth socket={socket} {...props} /> }/> }
<Route exact path="/admin" component={(props) => <Admin socket={socket} {...props} /> } />
<Route path="/s/back" component={(props) => <BackScreen socket={socket} {...props} /> } />
<Route path="/s/front" component={(props) => <FrontScreen socket={socket} {...props} /> } />
<Route path="/s/:id" component={(props) => <Screens {...props} socket={socket} workout={workout} /> } />
<Redirect to={'/s/1'} />
</Switch>
</BrowserRouter>
)
}
}
const ConnectedApp = connect(mapState)(App)
const rootEl = document.getElementById('root')
ReactDOM.render(
<Provider store={store}>
<ConnectedApp />
</Provider>,
rootEl,
)
Here's my Admin page.
import React, { Component, Fragment } from 'react'
import { Button, Grid, Header, Dimmer, Loader } from 'semantic-ui-react'
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { defaultTo } from 'ramda'
import './styles.css'
import WaitingList from './WaitingList'
import Stations from './Stations'
import AddUserModal from './AddUserModal'
class Admin extends Component {
state = {
loading: false,
time: '',
rest: false,
data: {
waiting: [],
queue: [],
},
startDate: new Date(),
showAddUserModal: false,
}
handleChange = date => {
const { socket } = this.props
this.setState({
startDate: date
})
socket.emit('GetWorkoutDate', { date })
}
UpdateTimer = ({ time, rest }) => {
this.setState({ time, rest })
}
UpdateQueue = ({ data }) => {
this.setState({ queue: defaultTo({}, data) })
}
GetCheckedInMemebers = ({ data }) => {
this.setState({ data })
}
componentDidMount() {
const { socket } = this.props
socket.on('connect', () => {
socket.emit('initAdmin')
})
socket.on('timer', ({ time, rest }) => this.UpdateTimer({ time, rest }))
socket.on('queue', data => this.UpdateQueue({ data }))
socket.on('GetCheckedInMemebers', data => this.GetCheckedInMemebers({ data }))
}
componentWillUnmount() {
const { socket } = this.props
socket.off('timer', this.UpdateTimer)
socket.off('queue', this.UpdateQueue)
socket.off('GetCheckedInMemebers', this.GetCheckedInMemebers)
}
addPersonToWaitingList = person => {
const { socket } = this.props
socket.emit('addUser', person)
}
removePersonFromList = (groupIndex, personIndex, list) => {
const { socket } = this.props
socket.emit('removeUser', { group: groupIndex, person: personIndex, list: list })
}
reorderWaitingList = waiting => {
const { data } = this.state
const { socket } = this.props
this.setState({ data: { ...data, waiting } })
socket.emit('reorder', waiting)
}
toggleTimer = () => {
const { socket } = this.props
socket.emit('toggleTimer')
}
render() {
const { loading, rest, time, data, showAddUserModal } = this.state
return (
<Fragment>
change workout date <DatePicker
dateFormat="M/d/yy"
selected={this.state.startDate}
onChange={this.handleChange}
/>
<Grid container columns={2} divided id="adminWrapper">
<Grid.Row className="fGrow">
<Grid.Column className="listWrapper">
<Header size="huge" textAlign="center">
Queue
<Button positive floated="right" onClick={() => this.setState({ showAddUserModal: true })}>
Add
</Button>
</Header>
<WaitingList
className="adminList"
waiting={data.waiting}
reorder={this.reorderWaitingList}
removeFromList={this.removePersonFromList}
/>
</Grid.Column>
<Grid.Column className="listWrapper">
<Header size="huge" textAlign="center">
Stations
</Header>
<Stations className="adminList" queue={data.queue}
removeFromList={this.removePersonFromList}
/>
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Button fluid color={rest ? 'red' : 'blue'} onClick={this.toggleTimer}>
<span>{time ? time : '0:00'}</span>
</Button>
</Grid.Row>
</Grid>
<AddUserModal
show={showAddUserModal}
handleClose={() => this.setState({ showAddUserModal: false })}
addUser={this.addPersonToWaitingList}
setLoading={isLoading => this.setState({ loading: isLoading })}
loading={loading}
/>
<Dimmer active={loading} page>
<Loader />
</Dimmer>
</Fragment>
)
}
}
export default Admin
New to node and react. Appreciate the guidance!
Edit: The calendar (date picker) is on another react page. GetWorkoutDate is being called. However, react never gets the data from the emit socket.emit('UpdateWorkouts', screenWorkouts). I verified the everything works correctly except getting the new data to update the react state.
Final Edit:
So for some reason I was not able to send the workout through props for the Screen page. Although, it is the correct way for react there just must be something going on with my environment. Here's what I did get working for me. When Screen page loads it loads the workout. Then I just added settimeout to repeat getting the workout every 5 secs.
socket.on('initScreen', async screen => {
setInterval(async function(){
const screenWorkouts = await workouts.current.filter(workout => workout.station == screen)
socket.emit('screenInfo', screenWorkouts)
}, 5000)
socket.emit('queueInfo', queue.screen(screen - 1))
socket.emit('timer', { time: timer.formatTime().formattedTime })
})
What's weird is after sending the workout to screens between 3 and 8 times correctly eventually it sends an empty array. So to prevent the workout from updating when it's empty I check it for length before I try and update the state.
UpdateScreenInfo = ({ data }) => {
if(data.length !== 0)
this.setState({ workout: defaultTo({}, data[0]) })
I'm awarding Daniele the points since they are about to expire and Daniele helped so much!
The problem is that each time you call openSocket you open a new connection to the server. Looking at your server code it seems that your 'GetWorkoutDate' message handler replies with 'UpdateWorkouts' message on the same socket connection; the problem is that 'UpdateWorkouts' is received by the react component sending the 'GetWorkoutDate' message and not by other react components due they open a new connection each.
The proper way to handle with WebSockets in a react app where more components needs to access the WebSocket is to open it only in the root component and passing it to child components as a property. Something like:
MainComponent extends React.Component {
componentDidMount() {
// Open the socket only in the main component
this.socket = openSocket(...);
}
componentWillUnmount() {
this.socket.close();
}
render() {
return (
<div>
{/* pass the socket as property to child components;
this can be repeated with all nested sub-component */}
<ChildComponent socket={this.socket}>
</div>
)
}
}
ChildComponent extends React.Component {
componentDidMount() {
const { socket } = this.props;
// create the required handlers and store them
this.handler = data => { /* do what you need with data */ };
// add the handlers to the socket
socket.on("message", this.handler);
}
componentWillUnmount() {
const { socket } = this.props;
// remove the handlers from the socket
socket.off("message", this.handler);
}
}
By this way you open a single connection and you share it between all components, now you can send messages to the server from a component and handle the response message on any other component.
Edit after last question update:
Two things:
the parent component is the root App component ok, but I can't still understand which is the component which emits the 'GetWorkoutDate' message (I was thinking it was the Screen 's parent component, but it seems I'm wrong); probably to find final solution we need to clarify this;
you are passing the socket (as a property) to the Route component, not to the Screen component: you need to change your routes as follows
<Route path="/s/:id" component={() => <Screens socket={socket} />} />
I checked better last version of your Screen component: you can't do this in componentDidMount method:
socket.on('timer', ({ time, rest }) => this.setState({ time, rest }))
you need to store the reference of the handler function in order to remove it later in componentWillUnmount method.
You can't do this in componentWillUnmount method:
socket.close();
now you have only one connection shared between all components of your app, if you close it once, you close it forever.
The strategy is: in componentDidMount method:
for each message (or more on general for each event), to create a handler function and store its reference
attache the referenced handler function to the desired message (or more in general, to the desired event)
then, in componentWillUnmount method:
to detach the handler function (throug the reference we still have) from the message (or more in general from the event),
by this way each time the component is mounted it starts listening on the desired messages/events, each time the component is unmounted it stops doing it and no actions will be performed on it while not mounted be the message/event handlers.
Edit:
Having circular import dependency is a bad idea: it's better to remove any var App = require('./index') (or similar) from child component files
But moreover, if the purpose of handleChange is only to emit something on the ws you don't need a so complicated design pattern: you can access the socket from Admin Component.
Probably what you need is
class App extends Component {
componentDidMount() {
// App component will never unmount: the reference for unmounting is not required
socket.on('UpdateWorkouts', ([workout]) => this.setState({ workout }));
}
render() {
const { workout } = this.state;
return (
...
<Route path="/s/:id" component={props => <Screens {...props, socket, workout} />} />
...
);
}
}
class Screen extends Component {
render() {
const { time, rest, queue } = this.state;
const { workout } = this.props;
...
}
}
You are calling componentDidMount function when socket emits UpdateWorkouts which is causing the loop. You should not call componentDidMount function of a react component, react handles the lifecycles methods itself. You can have another method to handle updates as following.
handleUpdateWorkouts = (updatedData) => {
//Update your workout, queue etc. whatever you update
this.setState({updatedData})
}
And assign this function as callback to on "UpdateWorkouts" events.
this.socket.on('UpdateWorkouts', (updatedData) => this.handleUpdateWorkouts(updatedData));
Make sure you are emitting GetWorkoutDate properly upon the calendar onChange.
this.socket.on('GetWorkoutDate', date); //something like this
If getNewWorkouts function is an async, then use await
socket.on('GetWorkoutDate', async function (date) {
await workouts.getNewWorkouts(date.date) //<----- here
const screenWorkouts = workouts.current.filter(workout => workout.station == 1)
console.log(screenWorkouts[0])
socket.emit('UpdateWorkouts', screenWorkouts)
})
I do have one solution at architect level which is, Return synchronous actions from the nodeJs sockets. So the moment client receive it, just dispatch the action received via socket and then automatically update it.
For eg: if socket returns
{
type: 'actionName',
data
}
then dispatching it directly would result in auto update of subscribed components.
I have a frontend with React native and I implemented the following:
import React, {Component} from 'react';
import Config from 'react-native-config';
import {
Button,
Alert,
Image,
Text,
View,
StyleSheet,
TouchableOpacity,
Platform,
CameraRoll,
} from 'react-native';
import {Container, Content, Icon} from 'native-base';
import {RNCamera} from 'react-native-camera';
import {SubHeader} from '../../components/headers';
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
backgroundColor: 'black',
},
preview: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
},
capture: {
flex: 0,
backgroundColor: '#fff',
borderRadius: 5,
padding: 15,
paddingHorizontal: 20,
alignSelf: 'center',
margin: 20,
},
});
export default class MainScreen extends Component {
constructor(props) {
super(props);
this.state = {
imageUri: null,
};
}
test = async () => {
if (this.camera) {
const data = await this.camera.takePictureAsync({
quality: 0.5,
base64: true,
});
const photo = {
name: data.fileName,
type: data.type,
uri:
Platform.OS === 'android'
? data.uri
: data.uri.replace('file://', ''),
};
this.setState({imageUri: data.uri}); //preview
const fdata = new FormData();
fdata.append('file', photo);
try {
let response = await fetch(`${Config.BASE_URL}/scan`, {
method: 'POST',
body: JSON.stringify(fdata),
//body: fdata //this launches a connection error
});
const res = await response.json();
return res;
} catch (error) {
console.error(error);
}
} else {
Alert.alert('debug', 'There is no camera');
}
};
render() {
const {navigate} = this.props.navigation;
return (
<View style={styles.container}>
<RNCamera
ref={ref => {
this.camera = ref;
}}
style={styles.preview}
type={RNCamera.Constants.Type.back}
flashMode={RNCamera.Constants.FlashMode.off}
captureAudio={false}
androidCameraPermissionOptions={{
title: 'Permission to use camera',
message: 'We need your permission to use your camera',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
}}
onGoogleVisionBarcodesDetected={({barcodes}) => {
console.log(barcodes);
}}
/>
<View>
<TouchableOpacity
onPress={this.test.bind(this)}
style={styles.capture}>
<Icon type="FontAwesome" ios="camera" android="camera" />
</TouchableOpacity>
</View>
</View>
//preview
<Image
style={{width: 66, height: 58}}
source={{
uri: this.state.imageUri,
}}
/>
</View>
);
}
}
On the backend with nodeJs express and multer:
app.post('/scan', uploader.upload.single('file'), ScanController.scan);
Multer is well implemented because it is working with postman and with frontend web application fucntionalities.
the image is shown on the android device, but I am getting always an undefined object on the backend, i do not know how to send this because is on base 64, How can I send it or receive correctly?
There is an open issue See here on react native about this, but I found a nice solution using rn-fetch-blob
as you may see in the documentation, you can implement the following:
First, delete the FormData instance, then change the fetch for RNFetchBlob.fetch
Code as follows
upload = async () => {
let ret = await RNFetchBlob.fetch(
'POST',
`${Config.BASE_URL}/scan`,
{
'Content-Type': 'multipart/form-data',
},
[
{
name: 'file',
filename: Date.now() + '.png',
type: 'image/png',
data: RNFetchBlob.wrap(data.uri),
},
],
);
return ret;
};
As you see, there is an array, where you can add the objects.
Multer implementation and RNCamera stays the same.
Hope this could be useful to someone!
I am building a mobile Chat app using Node.js, MySql, Sequelize, Socket, React Native and Redux.
I am trying to socket.emit the credential of the user to:
1) find or create the user and;
2) move to the next screen via the reducer.
I believe that either:
socket.emit('newUser', credentials) in ./store/index.js
doesn't work, and / or both
socket.on('newUser', credentials => {...} in ./index.js
socket.on('newUser', user => {...} in ./store/index.js
do not work, because nothing is added to database an I do not move to next screen. Simply, nothing happen when I enter some credentials and hit the button.
I am fairly new to development and tried to understand where is the problem by using multiple console.log (removed from the code below), as I don't know how else to test it.
I have also checked all other threads on socket.emit and on how to test if socket is working for the past few days, but I am still stuck.
Below is my code.
1) why socket.emit doesn't send (or socket.on doesn't listen)?
2) How can I test if socket is working (both on client and server side).
Thank you!!
./index.js
const server = require('http');
server.createServer(function (req, res) {}).listen(3000);
const io = require('socket.io')(server);
const { User, Conversation, Message } = require('./db').models;
const mobileSockets = {};
io.on('connection', socket => {
socket.on('newUser', credentials => {
const { name, password } = credentials;
Promise.all([
User.findOrCreate({
where: {
name,
password
}
}),
User.findAll()
])
.then(([user, users]) => {
mobileSockets[user[0].id] = socket.id;
socket.emit('userCreated', { user: user[0], users });
socket.broadcast.emit('newUser', user[0]);
});
});
});
./App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import { createStackNavigator } from 'react-navigation';
export default class App extends React.Component {
render() {
return (
<Provider store={ store }>
<RootStack />
</Provider>
);
}
}
import LoginScreen from './components/Login';
import Users from './components/Users';
import Chat from './components/Chat';
const RootStack = createStackNavigator({
Login: LoginScreen,
Users: Users,
Chat: Chat,
}, {
initialRouteName: 'Login',
navigationOptions: {
headerTitle: 'login to Chat!'
}
});
./components/Login.js
import React from 'react';
import { View, Text, TextInput, StyleSheet, TouchableOpacity } from 'react-native';
import { login } from '../store';
export default class LoginScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
password: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(type, value) {
this.setState({ [type]: value });
}
handleSubmit() {
login(this.state, this.props.navigation);
}
render() {
return (
<View style={ styles.container }>
<Text style={ styles.text }>Enter your name and password:</Text>
<TextInput
onChangeText={ value => this.handleChange('name', value) }
returnKeyType='next'
autoCapitalize='none'
autoCorrect={ false }
onSubmitEditing={ () => this.passwordInput.focus() }
style={ styles.input }
/>
<TextInput
onChangeText={ value => this.handleChange('password', value)}
secureTextEntry
returnKeyType='go'
autoCapitalize='none'
style={ styles.input }
ref={ input => this.passwordInput = input }
/>
<TouchableOpacity
onPress={ this.handleSubmit }
style={ styles.button }
>
<Text style={ styles.buttonText }>Login</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'powderblue',
height: '100%',
width: '100%'
},
text: {
fontSize: 20,
fontWeight: 'bold'
},
input: {
height: 40,
width: '90%',
borderWidth: 0.5,
borderColor: 'black',
backgroundColor: '#fff',
color: '#000',
textAlign: 'center',
marginTop: 10
},
button: {
width: '75%',
backgroundColor: 'blue',
borderRadius: 50,
alignItems: 'center',
justifyContent: 'center',
marginTop: 20,
paddingVertical: 15
},
buttonText: {
color: '#fff',
textAlign: 'center',
fontSize: 15,
fontWeight: 'bold',
}
});
./store/index.js
import { createStore, combineReducers } from 'redux';
import users, { gotUsers, gotNewUser } from './users';
import messages, { gotMessages, gotMessage } from './messages';
import user, { gotUser } from './user';
let navigate;
const reducers = combineReducers({ users, messages, user });
const store = createStore(reducers);
export default store;
export * from './users';
export * from './messages';
import socket from './socket';
});
socket.on('userCreated', response => {
const { user, users } = response;
store.dispatch(gotUser(user));
store.dispatch(gotUsers(users));
navigate('Users');
});
socket.on('newUser', user => {
console.log('store/index.js has received a "newUser"');
store.dispatch(gotNewUser(user));
});
export const login = (credentials, navigation) => {
socket.emit('newUser', credentials);
navigation = navigation.navigate;
};
./store/socket.js
import io from 'socket.io-client';
const socket = io('http://localhost:3000');
socket.connect();
export default socket;
It's not a real solution to the problem, but I've managed to make it work by using express.
./index.js
// replaced the connection part of the code with this
const app = require('express')();
const server = require('http').createServer(app);
const io = require('socket.io')(server);
app.get('/', function (req, res) {
res.send('Hello World');
});
server.listen(3000);
// the rest of the code goes here
I just want show a list of the site data to FlatList component,but I find an error:
TypeError: Cannot read property 'loginname' of undefined
therefore, I change '{item.author.loginname}' to '{item.author}', I get this error:
Unhandled JS Exception: Invariant Violation: Objects are not valid as a
React child (found: object with keys {loginname, avatar_url}). If you meant to render a collection of
Actually, property 'loginname' is exists. I am confused. Why?
Here is my code:
import React, { Component } from 'react';
import { Text, ScrollView, View, StyleSheet, FlatList,Image } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
stories: [{id: 1, text: 'option1'}, {id: 2, text: 'option2'}, {id: 3, text: 'option3'}],
isFetching: false,
};
}
componentDidMount() {
this.fetchData();
}
onRefresh() {
console.log('refreshing')
this.setState({ isFetching: true }, function() {
this.fetchData()
});
}
fetchData() {
var url = "https://cnodejs.org/api/v1/topics?limit=1&mdrender=true"
fetch(url, {method: "GET"})
.then((response) => response.json())
.then((responseData) => {
this.setState({stories: responseData.data,isFetching: false})
console.log( responseData.data[0].author.loginname,responseData.data[0].visit_count)
})
.done();
}
_renderItem = ({item}) => (
<View>
<Text>{item.author.loginname}</Text>
</View>
)
render() {
return (
<ScrollView style={styles.container}>
<View style={styles.wrapper}>
<Text>Hello World!!!</Text>
<FlatList
onRefresh={() => this.onRefresh()}
refreshing={this.state.isFetching}
data={this.state.stories}
keyExtractor={(item) => item.id}
renderItem={this._renderItem}
/>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
// alignItems: 'center',
// justifyContent: 'center',
paddingTop: 50,
backgroundColor: '#ecf0f1',
}
});
This issue occurs because of your initial state which is set in constructor. When first-time component try to render at that time it tacks story' state from constructor because of your API fetch tack some moment to complete call.
Just replace your constructore by following line.
constructor(props) {
super(props);
this.state = {
stories: [],
isFetching: false,
};
}
This problem occurred because your view loads first and then your api get called. So your stories is undefined.
Small Update to your code:
this.state = {
stories: null,
isFetching: false,
};
View inside render:
render() {
return (
<ScrollView style={styles.container}>
<View style={styles.wrapper}>
<Text>Hello World!!!</Text>
{this.state.stories !== null ?
<FlatList
onRefresh={() => this.onRefresh()}
refreshing={this.state.isFetching}
data={this.state.stories}
keyExtractor={(item) => item.id}
renderItem={this._renderItem}
/>
: null
}
</View>
</ScrollView>
);
}
Output:
Hello World!!
atian25