Image takes a source and a size. A static asset, require('../assets/covers/1.png'), is resolved by Metro at bundle time, with @2x and @3x variants picked for the screen density. A network image, { uri: 'https://example.com/1.png' }, can add headers, but its size is unknown, so you must give it a width and height. A data URI suits tiny images only: base64 adds a third to the size.
// A 2 x 3 pixel PNG, inlined as a data URI
const TINY = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAADCAIAAAA2iEnWAAAAHUlEQVQI12P4'
+ '/2DT+xwGxvc5DAwMDEwMDAwCJZsAWt0GgQGv7fkAAAAASUVORK5CYII=';
<Image source={require('../assets/covers/1.png')} style={styles.img} />
<Image source={{ uri: coverUrl(2) }} style={styles.img} />
<Image source={{ uri: TINY }} style={styles.img} alt="A data URI" />
// styles.img: { width: 120, height: 180, borderRadius: 6 }The first screen of the figure in Resize Modes and Image Caching shows the result: the 2 x 3 pixel data URI blurs into a smear. require() needs a string literal, so require('./covers/' + id + '.png') fails at bundle time; use a lookup object instead.