react native can't dynamically change Image component source uri - react-native

I'm facing a weird issue/bug with react native (0.61.5). I have a screen where a user can change his profile picture. The picture is fetched from redux.
const [pp, setPp] = useState(useSelector(state => state.profile.pp))
const ppChangeHandler = async () => {
try {
req = await fetch(...)
res = await req.json()
// res.url contains the url to the new uploaded image on the server
setPp(res.url)
} catch (e) {
console.log(e)
}
}
As you can see, I send a request to the server containing the new image (this is not included in the code, but it works), and as a response, I receive the newly generated url to the image. I want to update the profile picture on the screen to the new image once I receive the image url. But this does not work. The image dissapears and is not updated.
I'm thinking I'm facing this bug: Image Component will not update correctly when passing in new url #9195
I have tried the following things:
Adding a "key" prop to containing 'pp': <Image key={pp} source={{ uri: pp }} style={{ width: 100, height: 100 }} />
Adding "cache: reload" to the source: <Image source={{ uri: pp, cache: reload }} style={{ width: 100, height: 100 }} />
Does anyone has a tip/workaround for this problem? The "update" of the image works, when I refresh the app, the new profile picture is showed, but I want it to show immediately, not after refreshing the app.
Edit: I also tried it with FastImage (https://github.com/DylanVann/react-native-fast-image) but I get the same result.

Related

How to only load/render custom rendered image when it comes into view (react-native-render-html)

I am using react-native-render-html to render content that has images in it via a custom renderer. The issue I'm running into is some pages have dozens of images, and I would like to only download/render the ones I need that are in or near the viewport. The way the custom renderer is set up currently (via the documentation) it downloads all of them at once (How would I go about Implementing the logic into a more flatlist-like render system?
Here's the image renderer (if it helps):
const ImgRenderer = useCallback((props: any) => {
console.log('imgRendererProps: ', props)
const { Renderer, rendererProps } = useInternalRenderer('img', props);
const uri = rendererProps.source.uri;
const imgSource = {
...rendererProps.source,
// You could change the uri here, for example to provide a thumbnail.
uri: `https://home.website.com${uri?.split('about://')[1]}`
};
return (
<TouchableWithoutFeedback onPress={() => setModalImage(uri?.split('about://')[1] ?? null)}>
<Renderer {...rendererProps} source={imgSource} style={{resizeMode: 'contain'}} />
</TouchableWithoutFeedback>
);
}, [props.tnode?.init.nodeIndex])

Why useState hook doesn't update in WebView onScroll event?

I'm trying to create a workaround to calculate/get content height which should be rendered inside React Native WebView component.
For that Im artificially calling onScroll event with Javascript , then trying to update state with the actual content height. But even console log shows different values for content height, which should trigger state update , it doesnt happen. Only when really scrolling it gets updated. But its for sure that even without scrolling the event is triggered as console log is working.
Any idea why here state update fails? (In the code snippet some backticks are missing)
const [contentHeight, setContentHeight] = useState(10);
const webViewScript =
setTimeout(function() {
window.postMessage(document.body.scrollDown);
}, 1000);
true; // note: this is required, or you'll sometimes get silent failures
;
<WebView
injectedJavaScript={window.ReactNativeWebView.postMessage(${webViewScript})}
domStorageEnabled={true}
automaticallyAdjustContentInsets={false}
onScroll={(event) =>
setContentHeight(Number(event.nativeEvent.contentSize.height));
}
javaScriptEnabled
style={{ height: contentHeight }}
source={{ html: htmlTempl, baseUrl: '' }}
/>

React native Image ' Warning: Failed prop type: Invalid prop `source` supplied to `Image`. '

So this is my code
I already answered the question.
export const BigCard = ({Title, Image, Description}) => {
console.log(Image)
return(
<StyledBigCard>
<StyledImage source={{
uri: Image,
}}/>
<StyledStroke>
<StyledStrokeText>
<StyledPBigCard>{Description}</StyledPBigCard>
</StyledStrokeText>
<FontAwesomeIcon style={style.icon} size={ 22 } icon={faChevronRight} />
</StyledStroke>
</StyledBigCard>
)
};
this is were i import the images etc. it is set in PBS1Detail, its an object so when i go to PBS1Detail.Image i get the image
const db = firebase.firestore();
const [PBS1Detail, setPBS1Detail] = useState([]);
const [partnerLevel, setPartnerLevel] = useState('');
useEffect(()=> {
{/* DATABASE */}
db.collection('Track').get().then((snapshot) => {
let results = []
snapshot.docs.forEach(doc => {
results.push(renderTracks(doc))
}
)
setPBS1Detail(results)
});
then i push it all the way to the screen were i import Image
all my imports are correct, and the console.log() gives me the good url to the image.
now when i now reload the app it gives the error "Warning: Failed prop type: Invalid prop source supplied to Image."
then when i update the image component to
<StyledImage source={{uri: 'https://s3.eu-central-1.wasabisys.com/image-parttime-bijbelschool-jaar-1/Track1Module1Thumbnail.jpg'}}
and than save the changes it works
then when i update it to
<StyledImage source={{uri: Image}} />
and than save the changes it also works
so when i run it the first time it gives me this error than when i change it to an url and than change it back to the Image prop it works. but when i reload the app it gives me this error again.
how can i fix this?
The PBS1Detail is an empty array until you actually get the image data from Firestore.
So when the first render, I guess you are trying to pass undefined or some invalid values for the source prop.
How about you give a condition for the render part?
export const BigCard = ({Title, Image, Description}) => {
console.log(Image)
return(
<StyledBigCard>
{!!Image && (
<StyledImage source={{
uri: Image,
}}/>
)}
<StyledStroke>
<StyledStrokeText>
<StyledPBigCard>{Description}</StyledPBigCard>
</StyledStrokeText>
<FontAwesomeIcon style={style.icon} size={ 22 } icon={faChevronRight} />
</StyledStroke>
</StyledBigCard>
)
};
The problem is not my code above, what i did was that on my homescreen i sended wrong props to Image is send
Image={Require('../../assets/Image.png')}
thats why te error occurded. i have set it to
Image={'https://s3.eu-central-1.wasabisys.com/image-parttime-bijbelschool-jaar-1/Track1Module1Thumbnail.jpg'}
and it works perfectly!

React-Native WebView: Issue downloading and saving dynamically generated file

We are opening a Url (in WebView) which has a button that dynamically generates and downloads a file (e.g. PDF or Excel or any other type) based on user selected filters. This means that we do not have direct link to those files which can be downloaded using network request. In chrome, we can see downloaded file. However in WebView, we neither see download file (the way chrome shows at the bottom of window) nor we get any way to intercept/view the location where it is downloaded silently. Below is webview:
<WebView
ref={ref => (webview = ref)}
originWhitelist={['*']}
source={{ uri: pageURL }}
javaScriptEnabled={true}
startInLoadingState={true}
scalesPageToFit={true}
domStorageEnabled={true}
onError={(err) => console.log(err)}
onHttpError={(err) => console.log(err)}
allowFileAccess={true}
allowFileAccessFromFileURLs={true}
allowUniversalAccessFromFileURLs={true}
allowingReadAccessToURL={true}
mixedContentMode="always"
onFileDownload={({ nativeEvent }) => {
const { downloadUrl } = nativeEvent;
console.log(downloadUrl);
}}
onNavigationStateChange={handleWebViewNavigationStateChange}
onLoad={() => {
webview.injectJavaScript(jsCode);
}}
onMessage={event => {
const { data } = event.nativeEvent;
}}
/>
So, we have below queries:
How to know if WebView actually downloaded a file?
Is there a way to know where WebView downloads a file?
Is there a way to specify default location where WebView should download a file?
Environment:
Expo: 40.0.0,
React-native: 0.63,
react-native-webview: 11.0.0
We clicked on "Allow" when it asked for permission to download and store file on device. Also, onNavigationStateChange is not firing when button is clicked (may be because the file is downloaded on same page without navigating). We have onError and onHttpError which does not print anything so there does not seem to be any issue there.
Below is the code (C#) that gets executed when button is clicked to download file:
string attachment = "attachment; filename=temp.csv";
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AddHeader("content-disposition", attachment);
HttpContext.Current.Response.ContentType = "text/csv";
HttpContext.Current.Response.AddHeader("Pragma", "public");
// Prepare file content
HttpContext.Current.Response.Write(fileContent.ToString());
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.Close();

How Can I Open a Camera From Within my React Native App?

I'm working on an app where we want to allow our users (tech support personnel) to take a photo of an employee's badge so we can analyze the photo and extract the badge ID (we already have an open source algorithm to do this) to create a ticket. I have the app running a webview of the application used by helpdesk personnel from their desktops, as well as a button at the top to open the camera (currently it's just an alert). Code is below:
const onPress = () => {
Alert.alert('Will capture the badge using the camera');
};
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Button
onPress={onPress}
title="Capture Badge"
color="#841584"
accessibilityLabel="Capture a Customer's ID via a picture of their badge"
/>
<WebView
source={{uri: "www.example.com"}}
/>
</View>
);
}
Basically, what do I need to put in onPress so that I can take a picture and then send it to our algorithm (the algorithm will be just a function call at the end of onPress)? I've done research on using a camera in react native, but everything is taking about rendering a camera in the view. I only want to open a camera view if a user taps the "Capture Badge" button at the top of the app.
You can use react-native-image-cropper-picker. If I understood you correctly, you want to be able to launch the camera and then as a promise, send the image to your object detection algorithm. With this library you can launch the camera as follows:
openCamera(){
ImagePicker.openCamera({
width: 300,
height: 400,
cropping: true
}).then(image => {
//Your image
console.log(image);
});
}