Abh*_*osh 5 javascript reactjs redux react-redux
您好,我有一个关于我们最喜欢的Hooks API的问题!
我正在尝试从某个远程系统中获取照片。我将这些照片的Blob网址存储在我的由ID键入的减速器状态下。
我有一个包装在useCallback挂钩返回的备注版本中的辅助函数。useEffect我已经定义了这个函数。
我的回调又称辅助函数,取决于减速器状态的一部分。每次获取照片时都会更新。这将导致组件再次运行效果useEffect,从而导致无限循环。
component renders --> useEffect runs ---> `fetchPhotos` runs --> after 1st photo, reducer state is updated --> component updates because `useSelector`'s value changes ---> runs `fetchPhotos` again ---> infinite
Run Code Online (Sandbox Code Playgroud)
component renders --> useEffect runs ---> `fetchPhotos` runs --> after 1st photo, reducer state is updated --> component updates because `useSelector`'s value changes ---> runs `fetchPhotos` again ---> infinite
Run Code Online (Sandbox Code Playgroud)
我找到了另一种方式来获取照片,也就是通过调度动作并使用工作人员传奇来完成所有获取。这消除了对组件中的辅助对象的所有需要,因此不再需要useCallback,因此也无需重新渲染。然后,useEffect仅取决于dispatch哪个很好。
我正在努力使用hooks API的思维模式。我看到了明显的问题,但是我不确定如果不使用thunk和sagas之类的redux中间件,怎么办?
减速器功能:
const FormViewerContainer = (props) => {
const { completedForm, classes } = props;
const [error, setError] = useState(null);
const dispatch = useDispatch();
const photosState = useSelector(state => state.root.photos);
// helper function which fetches photos and updates the reducer state by dispatching actions
const fetchFormPhotos = React.useCallback(async () => {
try {
if (!completedForm) return;
const { photos: reducerPhotos, loadingPhotoIds } = photosState;
const { photos: completedFormPhotos } = completedForm;
const photoIds = Object.keys(completedFormPhotos || {});
// only fetch photos which aren't in reducer state yet
const photoIdsToFetch = photoIds.filter((pId) => {
const photo = reducerPhotos[pId] || {};
return !loadingPhotoIds.includes(pId) && !photo.blobUrl;
});
dispatch({
type: SET_LOADING_PHOTO_IDS,
payload: { photoIds: photoIdsToFetch } });
if (photoIdsToFetch.length <= 0) {
return;
}
photoIdsToFetch.forEach(async (photoId) => {
if (loadingPhotoIds.includes(photoIds)) return;
dispatch(fetchCompletedFormPhoto({ photoId }));
const thumbnailSize = {
width: 300,
height: 300,
};
const response = await fetchCompletedFormImages(
cformid,
fileId,
thumbnailSize,
)
if (response.status !== 200) {
dispatch(fetchCompletedFormPhotoRollback({ photoId }));
return;
}
const blob = await response.blob();
const blobUrl = URL.createObjectURL(blob);
dispatch(fetchCompletedFormPhotoSuccess({
photoId,
blobUrl,
}));
});
} catch (err) {
setError('Error fetching photos. Please try again.');
}
}, [completedForm, dispatch, photosState]);
// call the fetch form photos function
useEffect(() => {
fetchFormPhotos();
}, [fetchFormPhotos]);
...
...
}
Run Code Online (Sandbox Code Playgroud)
您可以将photoIdsToFetch计算逻辑包含到选择器函数中,以减少由状态更改引起的渲染数量。
const photoIdsToFetch = useSelector(state => {
const { photos: reducerPhotos, loadingPhotoIds } = state.root.photos;
const { photos: completedFormPhotos } = completedForm;
const photoIds = Object.keys(completedFormPhotos || {});
const photoIdsToFetch = photoIds.filter(pId => {
const photo = reducerPhotos[pId] || {};
return !loadingPhotoIds.includes(pId) && !photo.blobUrl;
});
return photoIdsToFetch;
},
equals
);
Run Code Online (Sandbox Code Playgroud)
然而,选择器函数不会被记忆,它每次都会返回一个新的数组对象,因此对象相等在这里不起作用。您需要提供 isEqual 方法作为第二个参数(它将比较两个数组的值是否相等),以便当 id 相同时选择器将返回相同的对象。您可以编写自己的库或deep-equals库,例如:
import equal from 'deep-equal';
Run Code Online (Sandbox Code Playgroud)
fetchFormPhotos将仅取决于[photoIdsToFetch, dispatch]这种方式。
我不确定你的减速器函数如何改变状态,所以这可能需要一些微调。这个想法是:仅从您依赖的存储中选择状态,这样存储的其他部分就不会导致重新渲染。
| 归档时间: |
|
| 查看次数: |
194 次 |
| 最近记录: |