I have written hooks for handling multiple image selection on my expo application.
import { useCallback, useState } from 'react';
import { CameraRoll } from 'react-native';
export function useCameraRoll({
first = 40,
assetType = 'Photos',
groupTypes = 'All',
}) {
const [photos, setPhotos] = useState([]);
const [after, setAfter] = useState(null);
const [hasNextPage, setHasNextPage] = useState(true);
const getPhotos = useCallback(async () => {
if (!hasNextPage) return;
const { edges, page_info: pageInfo } = await CameraRoll.getPhotos({
first,
assetType,
groupTypes,
...(after && { after }),
});
if (after === pageInfo.end_cursor) return;
const images = edges.map(i => i.node).map(i => i.image);
setPhotos([...photos, ...images]);
setAfter(pageInfo.end_cursor);
setHasNextPage(pageInfo.has_next_page);
}, [after, hasNextPage, photos]);
return [photos, getPhotos];
}
And I'm referencing the hooks function on another component like so:
import { useCameraRoll } from '../shared/hooks';
const _pickImage = async () => {
const [photos, getPhotos] = await useCameraRoll({first: 80})
};
And initiating the function to run onPress:
<TouchableOpacity style={styles.button} onPress={_pickImage}>
<Text style={{ color: 'white' }}>Add Photos</Text>
</TouchableOpacity>
However I'm getting: Invalid hook call. Hooks can only be called inside of the body of a function component.
Am I missing something? Please advise.
Thank you.
Updated code:
const RenderImagePicker = ({
// eslint-disable-next-line no-unused-vars
setFieldValue,
name,
value,
label,
meta: { touched, error },
}) => {
const [uploading, setUploading] = useState(false);
function MyComponent() {
const [photos, getPhotos] = useCameraRoll({ first: 80 });
}
return (
<TouchableOpacity style={styles.button} onPress={MyComponent}>
<Text style={{ color: "white" }}>Add Photos</Text>
</TouchableOpacity>
);
};
const _handleImagePicked = async (pickerResult) => {
try {
setUploading(true);
if (!pickerResult.cancelled) {
const uploadResponse = await uploadImageAsync(pickerResult.uri);
const uploadResult = await uploadResponse.json();
setFieldValue(name, uploadResult.location);
}
} catch (e) {
console.log(e);
// eslint-disable-next-line no-undef
alert('Upload failed, sorry :(');
} finally {
setUploading(false);
}
async function uploadImageAsync(uri) {
const apiUrl = 'http://xx:3000/upload';
const uriParts = uri.split('.');
const fileType = uriParts[uriParts.length - 1];
// eslint-disable-next-line no-undef
const formData = new FormData();
formData.append('photo', {
uri,
name: `photo.${fileType}`,
type: `image/${fileType}`,
});
const options = {
method: 'POST',
body: formData,
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
},
};
console.log(options);
return fetch(apiUrl, options);
}
};
const _maybeRenderUploadingOverlay = () => {
if (uploading) {
return (
<View>
<ActivityIndicator
color="#ff0000"
size="large"
style={{ alignSelf: 'center', flex: 1 }}
/>
</View>
);
}
};
function MyComponent() {
const [photos, getPhotos] = useCameraRoll({first: 80});
return (
<>
<TouchableOpacity style={styles.button} onPress={getPhotos}>
<Text style={{ color: 'white' }}>Add Photos</Text>
</TouchableOpacity>
{!!error && <Text style={{ color: 'red' }}>{error}</Text>}
{_maybeRenderUploadingOverlay()}
</>
);
}
};