2017-04-10 69 views
1

我想在客戶端刷新信息,當我在服務器上獲取帶有數據的POST請求時。React + Express - 提取新數據時的刷新頁面

目前看起來像這樣。我在服務器端有POST請求:

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); 
    } 
}) 

當我成功插入數據庫時​​,我想自動刷新客戶端。爲了顯示我使用MarkersList分量和MarkerPage組件從數據庫中標記JSON的相關信息:

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 - 客戶端:

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')); 

我應該怎麼做才能從服務器端發出類似於操作的動作,這將允許我在客戶端顯示數據庫的當前狀態?

回答

1

您必須執行由服務器端驅動的客戶端更新幾個方式:

客戶端超時或輪詢請求

相當不滿意的,因爲它要求你做出的執行時間預測服務器端代碼,它不是真正由服務器驅動的。 這裏有兩個解決方案,進行這樣的思考:用一個混合

在MarkerPage組件

只需使用一個mixin像react-timer-mixin調用this.props.fetchMarkers在MarkerPage組件每X秒(以2秒以下例子)。

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); 

爲了不嘗試避免mixin,它可以保證你的計時器將被組件銷燬。

在我看來,確保數據重裝不是組件目的。它唯一的目的是顯示。

在中間件或外部模塊中。

爲了避免從組件中重新加載數據,我更喜歡使用獨立代碼來發送到商店。它不會干擾組件代碼。 這裏是一個例子改編自我的申請:

index.js -client側:

import {fetchMarkers} from './actions'; 

function startAutoReloadMarkers(store) { 
    window.setInterval(() => { 
    store.dispatch(fetchMarkers()); 
    }, 2000); 
} 

const store= createStore(
    rootReducer, 
    composeWithDevTools(
    applyMiddleware(thunk) 
) 
) 

startAutoReloadMarkers(store) 

第二溶液。使用套接字並處於真正的實時環境中。

這是一個非常好的方式從反應/ redux優勢中獲利。 這是我在我的應用程序使用的解決方案:

在你的服務器端的登錄代碼:

// 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端:

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. 

如果你需要毫不遲疑一些幫助實施第二種解決方案。

+0

好的我使用套接字並思考它。怎麼只使用Redux?有可能這樣做嗎?我是React/Redux的新手。 – Mateusz

+0

@Mateusz:redux真的與套接字模式兼容。這是IMAO做的好方法。 –