当图像作为表单的一部分上载时,我试图启动加载微调器,并在Firebase中保存对图像的引用时停止它。
我的Actions.js文件中的此函数从给定的表单字段返回输入:
export const formUpdate = ({ prop, value }) => {
alert('update')
return {
type: FORM_UPDATE,
payload: { prop, value }
};
};
使用Connect,我使用formUpdate
在Form.js组件中存储不同表单字段的值-可以正常工作。
我在Actions.js中使用一个单独的函数来处理图片上传,上传后,我调用此函数将引用保存在Firebase中:
export const saveImageReference = (downloadUrl, sessionId) => {
const { currentUser } = firebase.auth();
firebase
.database()
.ref(`users/${currentUser.uid}/images`)
.push({
imageId: sessionId,
imageUrl: downloadUrl
})
.then(formUpdate({ prop: 'loading', value: false }));
};
我正在尝试让我的表单在上传过程中显示加载微调框。为此,我在formUpdate
的末尾使用saveImageReference
来分发loading
道具。但是,这不起作用。
formUpdate
作为.then()
块的一部分执行-我看到警报来确认这一点-但没有数据传递给Form组件。
我还尝试使用其他道具(例如“名称”)来查看它是否更新了表单字段,但是什么也没有发生。
我的redux-thunk
工作正常-我使用类似的方法在登录表单中显示了一个微调框-但是此操作似乎不想玩。
如果有帮助,请参见mapStateToProps
,来自我的表单组件:
const { name, location, loading } = state.testForm;
return {
loading,
name,
activity
};
};
export default connect(
mapStateToProps,
{ formUpdate, uploadImage }
)(Form);
更新
这是基于azundo答案的uploadImage代码。这不会执行:
export const uploadImage = (
uri,
mime = 'application/octet-stream'
) => dispatch => {
const { Blob } = RNFetchBlob.polyfill;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
const { currentUser } = firebase.auth();
console.log('Starting upload action...');
return new Promise((resolve, reject) => {
console.log('in promise 1');
const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri;
const sessionId = new Date().getTime();
// create a reference in firebase storage for the file
let uploadBlob = null;
const imageRef = firebase
.storage()
.ref(`user/${currentUser.uid}/images`)
.child(`image_${sessionId}`);
// encode data with base64 before upload
RNFetchBlob.fs
.readFile(uploadUri, 'base64')
.then(data => {
console.log('Encoding image...');
return RNFetchBlob.polyfill.Blob.build(data, {
type: `${mime};BASE64`
});
})
// put blob into storage reference
.then(blob => {
uploadBlob = blob;
console.log('uploading...');
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
console.log('Getting download URL...');
uploadBlob.close();
return imageRef.getDownloadURL();
})
.then(url => {
console.log('Saving reference...');
// setLoading();
resolve(url);
saveImageReference(url, sessionId);
})
.then(() => {
dispatch(formUpdate({ prop: 'loading', value: false }));
})
.catch(error => {
reject(error);
});
});
};
答案 0 :(得分:1)
根据您的描述,formUpdate
中的saveImageReference
调用实际上并没有调度您的操作,它只是调用简单的formUpdate
函数,该函数仅返回简单的操作对象。您需要找到某种方法来实际执行该操作。
假设uploadImage
是redux-thunk
动作,我建议您将对动作分派的知识保留在saveImageReference
函数之外,而应从uploadImage
分派:
export const saveImageReference = (downloadUrl, sessionId) => {
const { currentUser } = firebase.auth();
// note that we are now returning the firebase promise here
return firebase
.database()
.ref(`users/${currentUser.uid}/images`)
.push({
imageId: sessionId,
imageUrl: downloadUrl
});
};
const uploadImage = (arg1, arg2) => dispatch => {
// other upload code here prior to calling the firebase function...
saveImageReference(downloadUrl, sessionId).then(() => {
dispatch(formUpdate({prop: 'loading', value: false}));
});
})
答案 1 :(得分:0)
如果您尝试渲染加载器,则在等待异步操作时。您可以使用悬念。
这将是一个更好的选择。
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<React.Suspense fallback={<Spinner />}>
<div>
<OtherComponent />
</div>
</React.Suspense>
);
}
答案 2 :(得分:0)
经过大量调查,我解决了这个问题。我将saveImageReference()
从Actions.js移到了我的组件中:
addImage = () => {
ImagePicker.showImagePicker(response => {
if (!response.didCancel) {
// shows modal with a form for user to select an image and add metadata
this.setState({ showModal: true });
// set the loading spinner in the form to show image is uploading
this.props.formUpdate({ prop: 'loading', value: true });
// takes the selected image and invokes uploadImage
uploadImage(response.uri).then(url => {
// once image is uploaded, generate sessionId in the component, and invoke saveImageReference
const sessionId = new Date().getTime();
this.props.saveImageReference(url, sessionId);
});
}
});
};
uploadImage()
操作创建者使用成功上传的图像的URL进行解析,saveImageReference()
使用该URL创建引用。
保存引用后,saveImageReference()
将分派专门的操作来将加载设置为false。这是Actions.js的内容:
export const uploadImage = (uri, mime = 'application/octet-stream') => {
const { Blob } = RNFetchBlob.polyfill;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
const { currentUser } = firebase.auth();
console.log('Starting upload action...');
return new Promise((resolve, reject) => {
console.log('in promise');
const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri;
const sessionId = new Date().getTime();
// create a reference in firebase storage for the file
let uploadBlob = null;
const imageRef = firebase
.storage()
.ref(`user/${currentUser.uid}/images`)
.child(`image_${sessionId}`);
// encode data with base64 before upload
RNFetchBlob.fs
.readFile(uploadUri, 'base64')
.then(data => {
console.log('Encoding image...');
return RNFetchBlob.polyfill.Blob.build(data, {
type: `${mime};BASE64`
});
})
// put blob into storage reference
.then(blob => {
uploadBlob = blob;
console.log('uploading...');
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
console.log('Getting download URL...');
uploadBlob.close();
return imageRef.getDownloadURL();
})
.then(url => {
resolve(url, sessionId);
})
.catch(error => {
reject(error);
});
});
};
export const saveImageReference = (downloadUrl, sessionId) => {
const { currentUser } = firebase.auth();
console.log('Saving reference!');
return dispatch => {
firebase
.database()
.ref(`users/${currentUser.uid}/images`)
.push({
imageId: sessionId,
imageUrl: downloadUrl
})
.then(ref => {
console.log(ref.key);
dispatch(imageUploadComplete());
});
};
};
const imageUploadComplete = () => {
return dispatch => {
return dispatch({
type: IMAGE_CREATE,
payload: false
});
};
};
无论我尝试什么,我都无法从saveImageReference()
内分派其他操作-引入return dispatch
会冻结流程,没有它,我会得到dispatch is not defined
。
使用this.props.saveImageReference()
在组件级别调用此功能即可解决此问题。