我已经决定尝试effector
,我正在尝试找出用它替换我项目中redux的最佳方法。
每当我在React项目中使用redux时,我通常使用以下结构表示特性:
src
└── features
└── some_feature
├── components
│ └── MyComponent
│ └── index.ts
└── redux
├── actions.ts
├── types.ts
└── reducer.ts
与说,这是我的文件看起来像:
// src/features/some_feature/components/MyComponent/index.ts
import * as React from 'react';
import { useDispatch } from 'react-redux';
import { someFunction } from '../../redux/actions';
const MyComponent: React:FC = () => {
const dispatch = useDispatch();
React.useEffect(() => {
dispatch(someFunction());
}, [])
return <div>My component!</div>
}
我的行动:
// src/features/some_feature/redux/actions.ts
import { httpClient } from 'src/services/httpClient';
import { SOME_ACTION } from '../types';
type TSetSomeData = {
payload: {
someData: any;
}
}
const setSomeData = ({ payload: { someData } }): ThunkAction =>
(dispatch): void => {
dispatch({
type: SOME_ACTION,
payload: someData
})
};
export const someFunction = (): ThunkAction =>
async (dispatch): Promise<void> => {
try {
const { someData } = (await httpClient({
url: '/api/some-endpoint',
method: EMethodTypes.GET,
})) as {
someData: any;
};
dispatch(setSomeData({ payload: { someData } }));
} catch (err) {
console.log('Error in someFunction', err);
}
};
我的减速器:
// src/features/some_feature/redux/reducer.ts
import { AnyAction } from 'redux';
import { SOME_ACTION } from './types';
export type ISomeFeatureState = {
someData: any;
};
const initialState = {
someData: null,
};
const someFeatureReducer = (state: ISomeFeatureState = initialState, action: AnyAction): ISomeFeatureState => {
const { type, payload } = action;
if (type === SOME_ACTION) {
return {
...state,
someData: payload,
};
} else {
return {
...state,
};
}
};
export default someFeatureReducer;
types.ts
会有export const SOME_ACTION = '@redux/features/some_feature/some-action'
。
无论如何,下面是我的文件夹结构现在的样子:
src
└── features
└── some_feature
├── components
│ └── MyComponent
│ └── index.ts
└── effector
├── actions.ts
├── events.ts
└── store.ts
这些文件是:
// src/features/some_feature/effector/store.ts
import { createStore } from 'effector';
export const $someData = createStore(null, {
updateFilter: (someData) => !!someData,
});
// src/features/some_feature/effector/events.ts
import { $someData } from './store';
export const setSomeDataEvent = createEvent();
$someData.on(setSomeDataEvent, (state, payload) => payload);
// src/features/some_feature/effector/actions.ts
import { setSomeDataEvent } from './events';
type TSetSomeData = {
payload: {
someData: any;
};
};
export const setSomeData = ({ payload: { someData } }: TSetSomeData) => {
setSomeDataEvent(someData);
};
所以,它已经更干净,代码更少了。我之所以选择这样的结构和方法,是因为它和我现有的结构非常相似。
不管怎样,effector提供了不同的方法来改变存储,其中之一是在doneData
上:
// from the docs
import { createEvent, createStore, createEffect, sample } from 'effector'
const nextPost = createEvent()
const getCommentsFx = createEffect(async postId => {
const url = `posts/${postId}/comments`
const base = 'https://jsonplaceholder.typicode.com'
const req = await fetch(`${base}/${url}`)
return req.json()
})
const $postComments = createStore([])
.on(getCommentsFx.doneData, (_, comments) => comments)
const $currentPost = createStore(1)
.on(getCommentsFx.done, (_, {params: postId}) => postId)
sample({
source: $currentPost,
clock: nextPost,
fn: postId => postId + 1,
target: getCommentsFx,
})
nextPost()
在这里,一旦getCommentsFx
完成执行,存储$postComments
的值就被设置为getCommentsFx.doneData
解析为的值。
我遇到的麻烦是,使用相同的方法,但使它与我目前的项目"友好"。
我能想到的唯一方法是像这样重写someFunction
:
// src/features/some_feature/effector/actions.ts
import { createEffect } from 'effector';
import { httpClient } from 'src/services/httpClient';
import { $someData } from '../store';
import { setSomeDataEvent } from '../events';
type TSetSomeData = {
payload: {
someData: any;
}
}
export const setSomeData = ({ payload: { someData } }: TSetSomeData) => {
setSomeDataEvent(someData);
};
export const someFunction = (): ThunkAction =>
async (dispatch): Promise<void> => {
try {
const { someData } = await createEffect<{someData: any}>(async () =>
httpClient({
url: '/api/some-endpoint',
method: EMethodTypes.GET,
})
);
setSomeDataEvent(someData);
} catch (err) {
console.log('Error in someFunction', err);
}
};
但是我看不出使用createEffect
有什么意义,因为我可以这样做:
export const someFunction = (): ThunkAction =>
async (dispatch): Promise<void> => {
try {
const { someData } = (await httpClient({
url: '/api/some-endpoint',
method: EMethodTypes.GET,
})) as {
someData: any
}
setSomeDataEvent(someData);
} catch (err) {
console.log('Error in someFunction', err);
}
};
对此有什么建议吗?使用effector
而不使用createEffect
(或大多数其他通过其API提供的方法)是否合适?本质上,我只是创建存储并将事件绑定到它们,我觉得我没有按照预期的方式使用effector
,但我想不出更好的方法来重写它。
我能在这做什么?我该回终极吗?
1条答案
按热度按时间5gfr0r5j1#
你不应该在函数中创建效果,因为它是不可执行的,并且可能导致内存不足
使用您的代码片段,您可以创建效果
P.S.如果你需要调试这个效果,你可以使用
patronum
库中的debug
如果需要显示有关失败的http请求的信息,可以使用
并将此效果附加到存储
希望对你有帮助!