在带有 react-redux 的组件中使用动作的有效负载是错误的吗?
Is it wrong to use an action's payload inside a component with react-redux?
我想跟踪 API 我用 react-redux 发出的请求。为此,我想在操作中生成一个请求 ID,并通过有效负载将其传递给中间件和缩减器。然后,当我从我的组件分派操作时,我可以捕获请求 ID 并在请求进行时使用它来更新组件。
这是一些示例代码
州
export interface State {
[requestId: number]: Request;
}
export interface Request {
status: string;
error?: string;
}
动作
export function createRequest(): Action {
return {
type: "request",
payload: {
requestId: Math.random () // Make a random Id here
}
};
}
减速器
export function createRequestReducer(state: State): State {
return {
...state,
...{ state.payload.requestId: { status: "pending" } }
};
}
组件
interface props {
getRequestById: (id: number) => Request;
createRequest: () => number;
}
const component = (props: testProps): JSX.Element => {
const getRequestById = props.getRequestById;
const [requestId, setRequestId] = useState(null);
const [request, setRequest] = useState(null);
useEffect(() => {
if (requestId !== null) {
setRequest(getRequestById(requestId));
}
}, [requestId]);
return <div>The request status is {(request && request.status) || "Not started"}</div>;
}
function mapStateToProps(state: State) {
return {
getRequestById: (requestId: number): Request => {
getRequestById(state, requestId)
}
};
}
function mapDispatchToProps(dispatch: Dispatch) {
return {
createRequest: (): number => {
const action = createRequest();
dispatch(action);
return action.payload.requestId;
}
};
}
export default connect(mapStateToProps, mapDispatchToProps)(component);
我希望这会起作用,但它可能是一个巨大的反模式。是否不建议这样做?如果是,是否有其他选择?
我认为您的方法技术上完全没问题。只有 “逻辑上” 进行一些更改可能有意义:
是的,“action”应该被发送到 reducer(而不是在其他任何地方使用,尽管这在技术上没有问题)。
但是你可以做什么:
1。单独的操作和值
在action creator函数里面,你想做什么就做什么。
因此您可以分别创建和使用 action
和 requestId
。
这在技术上与您所做的完全相同,但在逻辑上是分开的。
例如:
function createRequest(){
const requestId = createUniqueId();
const action = { type: "request", payload: { requestId: requestId } };
return {
requestId: requestId, // <-- request id independent of the action
action: action, // <-- action independent of the request id
};
}
function mapDispatchToProps( dispatch: Dispatch ){
return {
createRequest: (): number => {
const { requestId, action } = createRequest();
dispatch( action ); // <-- action independent of the request id
return requestId; // <-- request id independent of the action
}
};
}
2。 “动作调度员”
我(显然还有其他人)喜欢使用我称之为“动作调度程序”的东西。
这是一个额外的步骤和更多的代码,但我认为当您习惯了这个概念时,它消除了必须将此类代码放在何处的任何疑虑。
例如:
// Create the action, and nothing else:
const createRequestActionCreator = function( requestId ){
return { type: "request", payload: { requestId: requestId } };
};
// Preper some data needed to create the action:
const createRequestActionDispatcher = function( dispatch ){
return function(){
const requestId = createUniqueId();
dispatch( createRequestActionCreator( requestId ) );
return requestId;
};
};
//
function mapDispatchToProps( dispatch: Dispatch ) {
return {
createRequest: (): number => {
const requestId = createRequestActionDispatcher( dispatch )();
return requestId;
}
};
}
2.a
此外,如果需要,您可以直接将这样的“动作调度程序”作为道具传递。
在这种情况下,它基本上取代了 mapDispatchToProps
中的函数,但可以重复使用,例如:
function mapDispatchToProps( dispatch: Dispatch ) {
return {
createRequest: createRequestActionDispatcher( dispatch ),
};
}
2.b
有些人更喜欢在这里使用 fat-arrow-function,我发现 更多 令人困惑,而不是更少,但一旦你习惯了这种模式,它看起来就更干净了:
const createRequestActionDispatcher = (dispatch: Dispatch) => (maybeSomeValue: MyType) => {
const requestId = createUniqueId();
dispatch( createRequestActionCreator( requestId ) );
return requestId;
};
备注:
我通常更喜欢保持一致,为此我应该始终(或从不)使用这些“动作调度程序”,
但我发现大多数时候我并不需要它们,但有时我发现它们非常有用。
所以我实际上在某些地方使用 dispatch( myAction )
而在其他地方使用 myActionDispatcher(value)(dispatch)
。
我不喜欢那样,但效果很好,我也没有更好的主意。
我想跟踪 API 我用 react-redux 发出的请求。为此,我想在操作中生成一个请求 ID,并通过有效负载将其传递给中间件和缩减器。然后,当我从我的组件分派操作时,我可以捕获请求 ID 并在请求进行时使用它来更新组件。
这是一些示例代码
州
export interface State {
[requestId: number]: Request;
}
export interface Request {
status: string;
error?: string;
}
动作
export function createRequest(): Action {
return {
type: "request",
payload: {
requestId: Math.random () // Make a random Id here
}
};
}
减速器
export function createRequestReducer(state: State): State {
return {
...state,
...{ state.payload.requestId: { status: "pending" } }
};
}
组件
interface props {
getRequestById: (id: number) => Request;
createRequest: () => number;
}
const component = (props: testProps): JSX.Element => {
const getRequestById = props.getRequestById;
const [requestId, setRequestId] = useState(null);
const [request, setRequest] = useState(null);
useEffect(() => {
if (requestId !== null) {
setRequest(getRequestById(requestId));
}
}, [requestId]);
return <div>The request status is {(request && request.status) || "Not started"}</div>;
}
function mapStateToProps(state: State) {
return {
getRequestById: (requestId: number): Request => {
getRequestById(state, requestId)
}
};
}
function mapDispatchToProps(dispatch: Dispatch) {
return {
createRequest: (): number => {
const action = createRequest();
dispatch(action);
return action.payload.requestId;
}
};
}
export default connect(mapStateToProps, mapDispatchToProps)(component);
我希望这会起作用,但它可能是一个巨大的反模式。是否不建议这样做?如果是,是否有其他选择?
我认为您的方法技术上完全没问题。只有 “逻辑上” 进行一些更改可能有意义:
是的,“action”应该被发送到 reducer(而不是在其他任何地方使用,尽管这在技术上没有问题)。
但是你可以做什么:
1。单独的操作和值
在action creator函数里面,你想做什么就做什么。
因此您可以分别创建和使用 action
和 requestId
。
这在技术上与您所做的完全相同,但在逻辑上是分开的。
例如:
function createRequest(){
const requestId = createUniqueId();
const action = { type: "request", payload: { requestId: requestId } };
return {
requestId: requestId, // <-- request id independent of the action
action: action, // <-- action independent of the request id
};
}
function mapDispatchToProps( dispatch: Dispatch ){
return {
createRequest: (): number => {
const { requestId, action } = createRequest();
dispatch( action ); // <-- action independent of the request id
return requestId; // <-- request id independent of the action
}
};
}
2。 “动作调度员”
我(显然还有其他人)喜欢使用我称之为“动作调度程序”的东西。 这是一个额外的步骤和更多的代码,但我认为当您习惯了这个概念时,它消除了必须将此类代码放在何处的任何疑虑。
例如:
// Create the action, and nothing else:
const createRequestActionCreator = function( requestId ){
return { type: "request", payload: { requestId: requestId } };
};
// Preper some data needed to create the action:
const createRequestActionDispatcher = function( dispatch ){
return function(){
const requestId = createUniqueId();
dispatch( createRequestActionCreator( requestId ) );
return requestId;
};
};
//
function mapDispatchToProps( dispatch: Dispatch ) {
return {
createRequest: (): number => {
const requestId = createRequestActionDispatcher( dispatch )();
return requestId;
}
};
}
2.a
此外,如果需要,您可以直接将这样的“动作调度程序”作为道具传递。
在这种情况下,它基本上取代了 mapDispatchToProps
中的函数,但可以重复使用,例如:
function mapDispatchToProps( dispatch: Dispatch ) {
return {
createRequest: createRequestActionDispatcher( dispatch ),
};
}
2.b
有些人更喜欢在这里使用 fat-arrow-function,我发现 更多 令人困惑,而不是更少,但一旦你习惯了这种模式,它看起来就更干净了:
const createRequestActionDispatcher = (dispatch: Dispatch) => (maybeSomeValue: MyType) => {
const requestId = createUniqueId();
dispatch( createRequestActionCreator( requestId ) );
return requestId;
};
备注:
我通常更喜欢保持一致,为此我应该始终(或从不)使用这些“动作调度程序”,
但我发现大多数时候我并不需要它们,但有时我发现它们非常有用。
所以我实际上在某些地方使用 dispatch( myAction )
而在其他地方使用 myActionDispatcher(value)(dispatch)
。
我不喜欢那样,但效果很好,我也没有更好的主意。