我有一个从数据库中提取的对象列表(在我的情况下为“相册”)。我需要编辑这些对象。 在useEffect钩子的编辑组件中,我启动了使用ID来获取所需专辑的操作。此操作有效。但是在同一个useEffect中,我试图获取触发操作redux状态之前的更改。现在我遇到了问题-我要获取的只是previos状态。 如何在当前的Redux状态的useEffect提取中实现?
我在这里看到过类似的问题,但是所有答案都对我的用例没有帮助。
我正在使用redux-thunk。
编辑组件。问题出现在setFormData中-它是从化简器中获取先前状态,而不是当前状态。似乎在状态由getAlbumById更改之前触发:
//imports
const EditAlbum = ({
album: { album, loading},
createAlbum,
getAlbumById,
history,
match
}) => {
const [formData, setFormData] = useState({
albumID: null,
albumName: ''
});
useEffect(() => {
getAlbumById(match.params.id);
setFormData({
albumID: loading || !album.albumID ? '' : album.albumID,
albumName: loading || !album.albumName ? '' : album.albumName
});
}, [getAlbumById, loading]);
const { albumName, albumID } = formData;
const onChange = e =>
setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = e => {
e.preventDefault();
createAlbum(formData, history, true);
};
return ( //code );
};
EditAlbum.propTypes = {
createAlbum: PropTypes.func.isRequired,
getAlbumById: PropTypes.func.isRequired,
album: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
album: state.album
});
export default connect(
mapStateToProps,
{ createAlbum, getAlbumById }
)(withRouter(EditAlbum));
操作:
export const getAlbumById = albumID => async dispatch => {
try {
const res = await axios.get(`/api/album/${albumID}`);
dispatch({
type: GET_ALBUM,
payload: res.data
});
} catch (err) {
dispatch({
type: ALBUMS_ERROR,
payload: { msg: err.response.statusText, status: err.response.status }
});
}
};
减速器
const initialState = {
album: null,
albums: [],
loading: true,
error: {}
};
const album = (state = initialState, action) => {
const { type, payload } = action;
switch (type) {
case GET_ALBUM:
return {
...state,
album: payload,
loading: false
};
case ALBUMS_ERROR:
return {
...state,
error: payload,
loading: false
};
default:
return state;
}
};
将感谢您的帮助/想法
答案 0 :(得分:2)
您应该将效果分成2个,以便在专辑ID从路线更改时加载专辑:
const [formData, setFormData] = useState({
albumID: match.params.id,
albumName: '',
});
const { albumName, albumID } = formData;
//only get album by id when id changed
useEffect(() => {
getAlbumById(albumID);
}, [albumID, getAlbumById]);
然后当数据到达时设置formData状态:
//custom hook to check if component is mounted
// this needs to be imported in your component
// https://github.com/jmlweb/isMounted
const useIsMounted = () => {
const isMounted = useRef(false);
useEffect(() => {
isMounted.current = true;
return () => (isMounted.current = false);
}, []);
return isMounted;
};
//in your component check if it's mounted
// because you cannot set state on unmounted component
const isMounted = useIsMounted();
useEffect(() => {
//only if loading is false and still mounted
if (loading === false && isMounted.current) {
const { albumID, albumName } = album;
setFormData({
albumID,
albumName,
});
}
}, [album, isMounted, loading]);
当您开始获取相册时,您的操作应将loading设置为true:
export const getAlbumById = albumID => async dispatch => {
try {
//here you should dispatch an action that would
// set loading to true
//dispatch({type:'LOAD_ALBUM'})
const res = await axios.get(`/api/album/${albumID}`);
dispatch({
type: GET_ALBUM,
payload: res.data
});
} catch (err) {
dispatch({
type: ALBUMS_ERROR,
payload: { msg: err.response.statusText, status: err.response.status }
});
}
};
更新检测为什么在不应该调用useEffect的情况下
您能用此输出更新问题吗?
//only get album by id when id changed
useEffect(() => {
console.log('In the get data effect');
getAlbumById(albumID);
return () => {
console.log('Clean up get data effect');
if (albumID !== pref.current.albumID) {
console.log(
'XXXX album ID changed:',
pref.current.albumID,
albumID
);
}
if (getAlbumById !== pref.current.getAlbumById) {
console.log(
'XXX getAlbumById changed',
pref.current.getAlbumById,
getAlbumById
);
}
};
}, [albumID, getAlbumById]);