2016-05-16 45 views
4

如何從標準JS日期對象格式化日期,該日期對象來自服務器,並通過REST API將其送入React,該REST API具有以下初始輸出:Redux Reducer在命中狀態之前格式化日期

"2016-05-16T13:07:00.000Z" 

成不同的格式?所以它被列爲DD MM YYYY

我可以做這個動作的減速通過操縱請求的結果,或有效載荷:

import { FETCH_BOOKS, FETCH_BOOK } from '../actions'; 

const INITIAL_STATE = { books: [], book: null }; 

export default function(state = INITIAL_STATE, action) { 
    switch(action.type) { 
     case FETCH_BOOK: 
      return { ...state, book: action.payload.data }; 
     case FETCH_BOOKS: 
      return { ...state, books: action.payload.data }; 
    } 
    return state; 
} 

用行動:

export function fetchBooks() { 
    const request = axios.get('/api/books'); 

    return { 
     type: FETCH_BOOKS, 
     payload: request 
    } 
} 

fetchBooks()是所謂的書籍的componentWillMount()方法React組件:

componentWillMount() { 
    this.props.fetchBooks(); 
} 

api retu RNS以下的結構化JSON:

[{"_id":0,"date":"2016-05-16T13:07:00.000Z","title":"Eloquent JavaScript","description":"Learn JavaScript"}] 

更新

非常感謝你妮可和nrabinowitz - 我已實現了以下的變化......在行動創造者

function transformDateFormat(json) { 
    const book = { 
     ...json, 
     id: json.data._id, 
     // date: new Date(moment(json.data.date).format('yyyy-MM-dd')) 
     date: new Date(json.data.date) 
    } 
    console.log(book); 
    return book; 
} 

export function fetchBook(id) { 
    const request = axios.get(`/api/books/${id}`) 
     .then(transformDateFormat); 

    return { 
     type: FETCH_BOOK, 
     payload: request 
    } 
}; 

我的記錄在轉換日期函數中加入了書對象,並且將iddate添加到對象的根,但json的結構實際上需要爲book.data.idbook.data.date。我不確定如何在transformDate函數內創建正確的結構以返回到動作創建者。

這是從轉換日期功能控制檯日誌簿對象:

Object {data: Object, status: 200, statusText: "OK", headers: Object, config: Object…} 
config: Object 
data: Object 
    __v:0 
    _id: "5749f1e0c373602b0e000001" 
    date: "2016-05-28T00:00:00.000Z" 
    name:"Eloquent JavaScript" 
    __proto__:Object 
date: Sat May 28 2016 01:00:00 GMT+0100 (BST) 
headers: Object 
id: "5749f1e0c373602b0e000001" 
request: XMLHttpRequest 
status: 200 
statusText: "OK" 
__proto__: Object 

我的函數需要放置的ID和日期的數據對象內。 (日期僅僅是標準的日期格式,什麼是錯的我的執行時刻(date: new Date(moment(json.data.date).format('yyyy-MM-dd'))回報Invalid date)再次

感謝您的幫助 - 真的很感激

+0

'new Date(moment(json.data.date)。format('yyyy-MM-dd'))'應該是'moment(new Date(json.data.date)).format('yyyy-MM-dd')'。時刻非常靈活,你應該可以完全放棄'新日期'部分。 – nrabinowitz

+0

感謝@nrabinowitz,試過這個,它是在操縱日期,但它是以'yyyy-06-Tue'出現的,而Redux窗體仍然不會加載日期值,就像其他值一樣。不知道現在該怎麼做 - 真正卡住了。 –

回答

7

我會立刻做這個轉換時的數據。到達前端,也就是在你的AJAX請求中,這樣,你的前端應用程序只能處理你打算修改的數據,而你的請求處理程序封裝和隱藏數據結構,就像它們從服務器提供並傳遞數據傳輸到前端應用程序所需的形狀

(在域驅動設計中, e「反腐敗層」的名稱)。

關於技術方案:

目前,您的事件負載包含了承諾的數據。你不會告訴我們你在哪裏調用fetchBooks(),即承諾執行的地方。這就是您需要進行數據轉換的地方。 (但個人而言,我寧願將數據轉換保留在fetchBooks函數中。)

而且,這就是你需要將數據發送到了Redux存儲點。爲了能夠異步地減少事件,你需要類似redux-thunk

一個解決方案可能是這樣的(我的道歉,我不是很使用的承諾經歷,所以我會在這裏使用回調,但也許你能以某種方式轉化,爲一個承諾):

export function fetchBooks(callback) { 
    const request = axios.get('/api/books') 
        .then(function (response) { 
         callback(transformData(response)); 
        }); 
} 

transformData應該執行從後端格式到前端格式的日期轉換。

別的地方你可能觸發獲取爲了獲取圖書發出的動作(姑且稱之爲loadBooks現在)。這就是你需要做的異步分派:

function loadBooks() { 
    return (dispatch, getState) => { 

     fetchBooks(response => { 
      dispatch(receiveBooks(response)); 
     }); 
    }; 
} 

function receiveBooks(data) { 
    return { 
     type: FETCH_BOOKS, 
     payload: data 
    }; 
} 

這樣,你纔會數據分派到了Redux店,一旦它實際上是從AJAX調用返回。

要使用redux-thunk,你需要注入其中間件到你的店是這樣的:

import thunkMiddleware from "redux-thunk"; 
import { createStore, applyMiddleware } from "redux"; 

const createStoreWithMiddleware = applyMiddleware(
    thunkMiddleware 
)(createStore); 

,然後通過你的減速作用來這家店。

請繼續詢問您是否有任何其他問題。

+0

謝謝妮可。技術上,我如何在Redux中執行此操作?我記錄到reducer中的控制檯payload.data,我得到三次未定義,然後是一個對象。大概是因爲這是一個Ajax請求,響應不是立即的?數據到達時如何轉換? –

+0

對不起,延遲了第二個孩子的忙碌。非常感謝您的幫助,我不確定您將回調翻譯爲承諾的含義。無法解決如何整合解決方案。我會繼續閱讀並嘗試解決它。真的很感謝幫助:) –

+0

不用擔心,享受家庭生活:-)我的意思是:axios是一個AJAX庫,與承諾一起工作,所以它返回一個承諾,並將該承諾存儲在redux存儲中(如果我理解正確)。所以在某些時候你會讀出承諾的價值。我的解決方案草圖不適用於承諾,因此您必須在訪問許諾的地方修改代碼。 – Nicole

3

我@Nicole同意在這裏 - 這是在AJAX客戶最好的處理。一種模式我經常在這裏用的是一個DataMapper,是這樣的:

function jsonToBook(json) { 
    // do whatever transformations you need here 
    var book = { 
     ...json, 
     id: json._id, 
     date: new Date(json.date) 
    } 
    // return the transformed, app-appropriate object 
    return book; 
} 

然後,在你的AJAX客戶端,您可以把轉換成.then電話:

const request = axios.get('/api/books') 
    .then(jsonToBook); 

這仍然會返回一個承諾,所以你的Promise中間件仍然可以按預期工作。其中一個優點是數據映射器真的很容易測試,但AJAX客戶端本身的邏輯更難。這裏

的另一點是,我建議你解析到一個Date對象,而不是一個格式化字符串。這是意見,但總的來說,我認爲格式化問題是視圖(即React組件)而不是存儲/縮減器的範疇。例如,傳遞Date而不是字符串可以更輕鬆地在應用的不同部分中對日期進行不同格式的設置。

對於實際的日期格式,請參閱Moment.jsD3's time-formatting utils

+0

謝謝,DataMapper是缺失的鏈接! – Nicole

+0

非常好,謝謝!我試圖實現,但不是很工作,更新原始帖子。再次感謝你們的幫助。 –

1

不必修改一次接收的響應,它可能是更好利用Axios的庫的transformResponse功能來解決該問題具體根據[Axios公司文檔] [1]和[示例] [2]的呼叫的一部分:

const ISO_8601 = /(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}.\d{3})Z/; 

export function fetchBooks() { 
    const request = axios.get('/api/books', { 
     transformResponse: axios.defaults.transformResponse.concat(function (data, headers) { 
     Object.keys(data).forEach(function (k) { 
      if (ISO_8601.test(data[k])) { 
      data[k] = new Date(Date.parse(data[k])); 
      } 
     }); 
     return data; 
     }) 
    }); 

    return { 
    type: FETCH_BOOKS, 
    payload: request 
    } 
} 

如果你想在日期一致地返回整個應用程序,然後攔截對象。請注意,以下示例僅將頂級對象從字符串更新爲日期而不是嵌套對象:

axios.interceptors.response.use(function (response) { 
    // Identify data fields returning from server as ISO_8601 formatted dates 
    var ISO_8601 = /(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}.\d{3})Z/; 

    var data = response.data 
    Object.keys(data).forEach(function (k) { 
    if (ISO_8601.test(data[k])) { 
     data[k] = new Date(Date.parse(data[k])); 
    } 
    }); 
    return response; 
}, function (error) { 
    // Do something with response error 
    return Promise.reject(error); 
}); 
+0

如何使它適用於嵌套對象? – swap0129