Reputation: 1193
I would like to refresh infos on client side, when I get POST request with data on server.
Currently it looks like this. I have POST request on server-side:
app.post('/login',jsonParser, function (req, res) {
if (!req.body) return res.sendStatus(400);
if(req.body){
console.log(req.body);
mongodb.connect(dbUrl,function(err,db){
db.collection('markers').insertOne(req.body);
});
return res.sendStatus(200);
}
})
When I get succesful insertion to database I would like to refresh client-side automatically. To display infos from markers' JSON from database I am using MarkersList component and MarkerPage component:
MarkersList.js
export default function MarkersList({markers}) {
const emptyMessage=(
<p> There are no coordinates to display </p>
);
const markersList=(
<div>{markers.map(marker=> <p>{marker.title}</p>)}</div>
);
return(
<div>
{markers.length === 0 ? emptyMessage:markersList}
</div>
);
}
MarkersList.propTypes={
markers:React.PropTypes.array.isRequired
}
MarkerPage.js
import React from 'react';
import MarkersList from './MarkersList';
import {connect} from 'react-redux';
import {fetchMarkers} from './actions';
class Markers extends React.Component{
componentDidMount(){
this.props.fetchMarkers();
}
render(){
return(
<div>
<p>LISTA</p>
<MarkersList markers={this.props.markers}/>
</div>
)
}
}
Markers.propTypes={
markers: React.PropTypes.array.isRequired,
fetchMarkers: React.PropTypes.func.isRequired
}
function mapStateToProps(state){
return{
markers:state.markers
}
}
export default connect(mapStateToProps,{fetchMarkers})(Markers);
actions.js
export const SET_MARKERS='SET_MARKERS';
export function setMarkers(markers){
return{
type:SET_MARKERS,
markers
}
}
export function fetchMarkers(){
return dispatch => {
fetch('/api/markers')
.then(res=>res.json())
.then(data=>dispatch(setMarkers(data.markers)));
;
}
}
index.js -client side:
const store= createStore(
rootReducer,
composeWithDevTools(
applyMiddleware(thunk) //dispach asynchronous actions
)
)
render(
<BrowserRouter>
<Provider store={store}>
<div>
<Route path="/" component={App}></Route>
<Route path="/markers" component={Markers}></Route>
</div>
</Provider >
</BrowserRouter>
,document.getElementById('app'));
What should I do to emit something like action from server-side that will allow me to display current state of database on the client-side?
Upvotes: 1
Views: 2597
Reputation: 5212
You have several way to perform client-side update driven by server-side :
Pretty unsatisfying because it asks you to make prediction about the execution time of the server-side code and it is not really driven by the server. Here are two solutions to perform such a think :
Just use a mixin like react-timer-mixin to call this.props.fetchMarkers in MarkerPage component every X seconds (2 seconds in the bellow example).
import React from 'react';
import TimerMixin from 'react-timer-mixin';
import MarkersList from './MarkersList';
import {connect} from 'react-redux';
import {fetchMarkers} from './actions';
class Markers extends React.Component{
componentDidMount(){
this.props.fetchMarkers();
TimerMixin.setTimeout(() => {
this.props.fetchMarkers();
},2000);
}
render(){
return(
<div>
<p>LISTA</p>
<MarkersList markers={this.props.markers}/>
</div>
)
}
}
Markers.propTypes={
markers: React.PropTypes.array.isRequired,
fetchMarkers: React.PropTypes.func.isRequired
}
function mapStateToProps(state){
return{
markers:state.markers
}
}
export default connect(mapStateToProps,{fetchMarkers})(Markers);
To not try to avoid the mixin it assures you that the timer will be destroyed with the component.
In my opinion, it's not the component purpose to ensure the data-reload. Its only purpose is to display.
To avoid the data-reload from the component, I prefer the use of an independant code that will dispatch to the store. It won't interfer with the component code. Here is one example adapted from my application :
index.js -client side:
import {fetchMarkers} from './actions';
function startAutoReloadMarkers(store) {
window.setInterval(() => {
store.dispatch(fetchMarkers());
}, 2000);
}
const store= createStore(
rootReducer,
composeWithDevTools(
applyMiddleware(thunk)
)
)
startAutoReloadMarkers(store)
It's a very good way to profit from the react/redux advantages. Here is the solution I used in my application :
In your server-side login code :
// On user login (using a websocket), I trigger a call to an external service wich will respond later (my seneca service is the equivalent of your mongodb insert)
seneca().use(senecaTransactions).act({ cmd: handleAutomaticOperations, userId: user._id }, (error, transactions) => {
if(error) {
// You don't need thios
reject(error);
} else {
// You don't need this
resolve(true);
// Here I will notify the client that some transactions have been updated/added
socket.emit(TRANSACTION_UPDATED, transactions);
}
});
index.js -client side:
import Socket from '../Socket';
import { TRANSACTION_UPDATED } from '../constants/SocketActions';
export function startTransactionsMiddleware(store) {
Socket.on(TRANSACTION_UPDATED, (transaction) => {
// The equivalent of your dispatch(fetchMarkers()
store.dispatch(transactionUpdated(transaction));
});
}
// Same think that the previous example
startTransactionsMiddleware(store);
This way once the TRANSACTION_UPDATED is trigerred in the server my display will be updated thanks to redux.
To not hesitate if you need some help for implementing the second solution.
Upvotes: 1