在达到状态之前在Redux Reducer中设置日期格式
Format date in Redux Reducer before it hits state
如何从标准JS日期对象中格式化日期,该对象来自服务器,并通过RESTAPI通过Redux输入React,其初始输出为:
"2016-05-16T13:07:00.000Z"
换成不同的格式?所以它被列为DD MM YYYY
?
我可以在Reducer of Action中通过操纵请求结果或有效载荷来做到这一点吗:
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
}
}
在Books React组件的componentWillMount()
方法中调用fetchBooks()
:
componentWillMount() {
this.props.fetchBooks();
}
api返回以下结构化JSON:
[{"_id":0,"date":"2016-05-16T13:07:00.000Z","title":"Eloquent JavaScript","description":"Learn JavaScript"}]
更新
非常感谢Nicole和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
}
};
我正在transform-date函数中记录book对象,它正在向对象的根添加id
和date
,但json的结构实际上需要是book.data.id
和book.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和日期放在数据对象中。(日期只是标准的日期格式,因为我的moment实现有问题(date: new Date(moment(json.data.date).format('yyyy-MM-dd'))
返回Invalid date
)。
再次感谢你的帮助,真的很感激。
当数据到达前端时,即在您的AJAX请求中,我会立即执行此转换。这样,您的前端应用程序只在您希望对数据进行整形时使用数据,而您的请求处理程序在服务器提供数据结构时封装并隐藏数据结构,并以所需的形状将数据传递给前端应用程序。
(在领域驱动设计中,这被称为"反腐败层")。
关于技术解决方案:
目前,您的事件负载包含对数据的承诺。您没有向我们显示您在哪里调用fetchBooks()
,即在哪里执行承诺。这就是您需要进行数据转换的地方。(但就我个人而言,我宁愿将数据转换保留在fetchBooks
函数中。)
此外,这也是您需要将数据发送到redux存储的地方。为了能够异步减少事件,您需要类似redux-thunk
的东西。
解决方案可能是这样的(很抱歉,我在使用promise方面不是很有经验,所以我会在这里使用回调,但也许你可以以某种方式将其转换为promise):
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
};
}
这样,只有在AJAX调用实际返回数据后,您才会将数据分派到redux存储。
要使用redux-thunk
,您需要将其中间件注入到您的商店中,如下所示:
import thunkMiddleware from "redux-thunk";
import { createStore, applyMiddleware } from "redux";
const createStoreWithMiddleware = applyMiddleware(
thunkMiddleware
)(createStore);
然后将减速器函数传递到此存储。
如果您还有其他问题,请继续提问。
我同意@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,所以您的promise中间件应该仍然可以按预期工作。这样做的一个优点是,数据映射器确实很容易测试,但AJAX客户端本身的逻辑更难。
这里的另一点是,我建议解析Date对象,而不是格式化的字符串。这是意见,但总的来说,我认为格式化问题是视图的领域(即React组件),而不是存储/还原器。例如,传递Date
而不是字符串可以更容易地在应用程序的不同部分以不同的方式设置日期格式。
有关实际日期格式,请参阅Moment.js或D3的时间格式实用程序。
与其在收到响应后修改响应,不如使用axios库的transformResponse函数作为[axios docs][1]和[example][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);
});
serify-deserify
将不可序列化的值可逆地转换为可序列化的,然后再转换回来。它本机支持BigInt
、Date
、Map
和Set
,您可以轻松添加对自定义类型的支持。
该包包括一个Redux中间件,该中间件在进入商店的过程中应用串行化转换。在deserify
函数中包装检索函数,以便将结果转换为适当的类型。
全面披露:我是软件包的创建者!
- 在输入类型日期中设置日期
- 在达到状态之前在Redux Reducer中设置日期格式
- Javascript设置日期不起作用,显示错误的时间
- 如何在我的情况下设置日期格式
- 时间戳日期&时间格式-应用程序脚本-设置日期和时间格式
- 引导日期选取器在显示时与在值上设置日期的格式不同
- 设置日期变量的格式
- Java 脚本 设置日期的最小值和最大值属性
- Javascript Date - 只设置日期,忽略时间
- 使用angular-moment.js设置日期格式
- Moment会在设置日期时自动更正无效日期
- Moment.js:根据浏览器语言设置日期格式
- 以给定的精度设置日期格式
- 使用即时Angularjs设置日期格式
- 使用DateAdd()在Javascript/Classic ASP中设置日期格式
- 从 UTC 字符串设置日期格式
- 如何设置日期滑块的选定范围的最小值
- 以角度格式设置日期格式
- 以角度设置日期格式
- 在 JavaScript 中设置日期时间顺序