How can I have a Dynamic Image uri that is not always defined in React Native? - rest

I am trying to get the filename of my image from a fetch to my rest service. But React tries to require the image before the call has the filename so ofcourse it can't find the image and gives me a 500 error back.
Is there any way to solve or work around this?
I am trying to get the filename from a json which it gets back from the fetch.
The function in which this is supposed to happen
nextPerson = () => {
var numberOfPersons = Object.keys(this.state.peopleList).length;
if (this.state.personIndex < numberOfPersons) {
person = this.state.peopleList[this.state.personIndex]
this.setState({currentPerson:person});
this.setState({image : require('../img/' + Object(this.state.currentPerson.gebruikerFoto).url)});
this.state.personIndex++;
}
}
The render of my component
render() {
var img = this.state.image;
return (
<View style={styles.container}>
<Image style={styles.image} source={img} />
<Text style={styles.persoonNaam}>{this.state.currentPerson.gebruikerNaam}</Text>
<Text style={styles.persoonBio}>{this.state.currentPerson.biografie}</Text>
<TouchableOpacity onPress={this.likePersoon}>
<Text>Like</Text>
</TouchableOpacity>
</View>
);
}

You need to keep your component in loading state, by rendering a shimmer component (react-native-shimmer) or just use ActivityIndicator from react native, until your api call finishes. Once the data is available you can render the Image component.
render() {
if (!this.state.imageUri) return <ActivityIndicator />; // keep showing the loader until the api call is done. Update the state once the call is successful.
return (
<Image /> // your image component
)

see this example:
renderItem = ({item})=>{
return(
<TouchableOpacity onPress={ () => this._openViewPage(item.id, item.cat_id,this.state.token)} style={styles.boxContainer}>
<View style={styles.BoxLeft}>
<H1>{item.title}</H1>
<H2 style={{flexWrap: 'wrap', textAlign: 'right',}}>{item.short_description}</H2>
</View>
<View style={styles.boxRight}>
<Image source={{uri: item.image}} style={{width: 100, height: 100 }} />
</View>
</TouchableOpacity>
)
}
annd in the render of your component you can use it:
<FlatList
data= {this.state.dataSource}
renderItem={this.renderItem}
keyExtractor = { (item, index) => index.toString() }
style={{marginBottom:100}}
/>

Related

How i can set user Image & avatar in the list, if user upload image then show user image otherwise its show the avatar

const ImageDetail = ({ record = {} }) => {
return (
<div>
<Avatar style={{ backgroundColor: colour() }}>
{record.MemberFirstName && record.MemberFirstName.charAt(0)}
{record.MemberLastName && record.MemberLastName.charAt(0)}
</Avatar>
</div>
)
}
This is my Avatar code.
<List>
<Datagrid>
<ImageField label="Image" source="MemberImage.src" />
<ImageDetail source="" label="Image" />
</Datagrid>
</List>
Now I'm using both but I need only one at a time if the user uploads an image show the image otherwise it shows an avatar.
It is enough to pass the image source to the <Avatar/>: src prop and it will do the rest - display the image if available or the default avatar image if not.
<List>
<Datagrid>
<AvatarField label="Image" source="MemberImage.src"/>
</Datagrid>
</List>
...
const AvatarField = ({record, source}) => {
return <Avatar src={record && record[source]}/>
}
Though if you really want to access nested property of the record - e.g. MemberImage["src"] - you might need to swap record[source] with lodash's get utility method -> get(record, source)
const ImageDetail = ({ source, record = {} }) => {
return (
<div>
{(record.MemberImage != undefined && record.MemberImage.src != undefined) ? (
<img width='35' height='35' src={`${record.MemberImage.src}`} />)
: (<Avatar style={{ backgroundColor: colour() }}>
{record.MemberFirstName && record.MemberFirstName.charAt(0)}
{record.MemberLastName && record.MemberLastName.charAt(0)}
</Avatar>)
}
</div >
)
}

How to display binary data as image in react-native

I am very new to react, an i have a use case like, getting the books details in a API response with the image. I need to iterate over the response and I need to display the image.
as suggested displaying binary data as image below is the code i have used for this. But image is not displayed. Any suggestions would be appreciated. What Am i doing wrong?
<View>
<FlatList data={books} renderItem={
data => {
console.log("data is -? " + books.author);
//const buffer = Buffer.from(data.item.image.data, 'binary').toString('base64');
/* let image = btoa(
new Uint8Array(data.item.image.data)
.reduce((d, byte) => d + String.fromCharCode(byte), '')
);*/
const encoded = data.item.image.data;
<View style={styles.imageContainer}>
<Image
source={{
uri: `data:image/jpeg;base64,${encoded}`
} }
//source="{URL.createObjectUrl(encoded)}"
style={styles.stretch}
/>
</View>
}
} />
</View>
Here am sharing the solution how did solve the problem, hope this might help someone. Just sharing the working code.
<FlatList data={books} keyExtractor={(item, index) => item.id.title+index}
renderItem={({ item }) =>
<Item title={item} />
} />
function Item({ title }) {
let ed = 'data:image/png;base64,' + title.image.data;
return (
<View>
<Image source={{ uri: ed }} /></View>
);
}

ag-Grid Switch goes from checked to unchecked upon down sroll

Getting this weird error where any checked material UI switch becomes unchecked as I scroll down out of that data view.
Below is the Switch return with conditional rendering.
let freeTier = props.params.data.tier;
return freeTier === "FREE" ? (
<FormGroup>
<FormControlLabel
control={
<Switch
disableRipple
focusVisibleClassName={classes.focusVisible}
classes={{
root: classes.root,
switchBase: classes.switchBase,
thumb: classes.thumb,
track: classes.track,
checked: classes.checked
}}
{...props}
/>
}
/>
</FormGroup>
) : null;
And this is where I call the above into cellRendererFramework
cellRendererFramework: params => {
const handleClick = params => {
console.log(params.data);
};
return (
<PaypalSwitch
params={params}
data={params.data}
otherProps={this.props}
onClick={() => handleClick(params)}
/>
);
}
From what it seems like the grid re-renders? I'm getting this error.
ag-Grid: React Component 'cellRendererFramework' not created within
1000ms

Use 'navigation' and 'route' inside header present in class - React-navigation v5

I'm stuck as I want to switch to the V5 version of react-navigation.
With v4, I used to pass my params and use them with :
Set :
this.props.navigation.navigate('MyDestination', {myParam: 'value'})
Get :
this.props.navigation.getParam('myParam')
With v5, some things changed and I now can't use the this.props.navigation since it's not seemed to be known by the app.
My code is splitted so I have my App.js that only refer to the Navigation class :
import React from 'react';
import { StyleSheet, Text, View } from 'react-native'
import Navigation from './navigation/Navigation'
export default function App() {
return (
<Navigation/>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Then my Navigation file contains all the navigation mechanism (I did not added my TabBar yet, since I want to fix the base navigation first) :
import { NavigationContainer } from '#react-navigation/native'
import { createStackNavigator } from '#react-navigation/stack'
import { createBottomTabNavigator } from 'react-navigation-tabs'
import { StyleSheet, Image } from 'react-native'
import React from 'react'
import Home from '../components/Home'
import LendList from '../components/LendList'
import AddMoney from '../components/AddMoney'
import AddStuff from '../components/AddStuff'
import Settings from '../components/Settings'
import Test from '../components/Test'
function HomeScreen() {
return(
<Home/>
)
}
function LendListScreen() {
return(
<LendList/>
)
}
const Stack = createStackNavigator()
function App() {
return(
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home"
component={Home}
options={{ title: "Home Page"}}
/>
<Stack.Screen name="LendList"
component={LendList}
options={{ title: 'Liste' }}
/>
<Stack.Screen name="AddMoney"
component={AddMoney}
options={{ title: "Ajout Money"}}
/>
<Stack.Screen name="AddStuff"
component={AddStuff}
options={{ title: "Ajout Stuff"}}
/>
<Stack.Screen name="Settings"
component={Settings}
options={{ title: "Settings"}}
/>
<Stack.Screen name="Test"
component={Test}
options={{ title: "Test"}}
/>
</Stack.Navigator>
</NavigationContainer>
)
}
export default App
And then come each of my pages (coded with classes), and here is one example, Home.js (I removed all the Style part to shorten the code displayed here) :
import React from 'react'
import { StyleSheet, Text, Image, View, Button, TouchableOpacity } from 'react-native'
import Moment from 'react-moment'
import { CommonActions } from '#react-navigation/native'
import { useNavigation } from '#react-navigation/native'
class Home extends React.Component {
static navigationOptions = () => {
return {
headerRight: () => <TouchableOpacity style={styles.settings_touchable_headerrightbutton}
onPress={() => this.goToSettings()}>
<Image style={styles.settings_image}
source={require('../assets/ic_settings.png')} />
</TouchableOpacity>
}
}
constructor(props) {
super(props)
this._goToSettings = this._goToSettings.bind(this)
}
_updateNavigationParams() {
navigation.setParams({
goToSettings: this._goToSettings
})
}
componentDidMount(){
console.log("navigation")
this._updateNavigationParams()
}
_checkMoneyDetails(navigation){
navigation.navigate('LendList', {type: 'Money'})
}
_checkStuffDetails(navigation){
navigation.navigate('LendList', {type: 'Stuff'})
}
_checkPeopleDetails(navigation){
navigation.navigate('LendList', {type: 'People'})
}
_goToSettings = () => {
navigation.navigate('Settings')
}
render(){
const date = new Date();
const { navigation } = this.props;
return(
<View style={styles.main_container}>
<View style={styles.header_view}>
<Text style={styles.header_text}>GiViToMe</Text>
<Text style={styles.header_text}>Nous sommes le :{' '}
{/* TODO: Penser à gérer ensuite les formats de date étrangers */}
<Moment element={Text} format="DD/MM/YYYY" date={date}/>
</Text>
</View>
<View style={styles.lend_view}>
<Text style={styles.title_lend_text}>Vos prêts :</Text>
<View style={styles.money_stuff_view}>
<View style={styles.money_view}>
<View style={styles.money_data_view}>
<Image source={require('../assets/ic_money.png')} style={styles.home_img} />
<Text>XXX $</Text>
</View>
<Button title='Money' onPress={() => {this._checkMoneyDetails(navigation)}}/>
</View>
<View style={styles.stuff_view}>
<View style={styles.stuff_data_view}>
<Image source={require('../assets/ic_box.png')} style={styles.home_img} />
<Text>XXX objets</Text>
</View>
<Button title='Stuff' onPress={() => {this._checkStuffDetails(navigation)}}/>
</View>
</View>
<View style={styles.people_view}>
<View style={styles.people_data_view}>
<Image source={require('../assets/ic_people.png')} style={styles.home_img} />
<Text>XXX people</Text>
</View>
<Button title='People' onPress={() => {this._checkPeopleDetails(navigation)}}/>
</View>
</View>
<View style={styles.footer_view}>
<Text style={styles.text_footer_view}>a.vescera inc.</Text>
</View>
</View>
)
}
}
export default Home
My problem is that, per the online documentation, I saw that to use "navigation" or "route" within a class, I should use the const navigation = { this.props } after the render() function.
This problem is that, to use one specific function within the header, I have to bind it after the componentDidMount() function, but the value present under render() is not yet known.
How could I solve this ? (sure that in the given example, having all the code in the navigation part allow to use navigation and route easily but you understand that I have to split my code.
Thanks.
Ok, so each time the same, I try many days solving my problem, and when I finally decide to post on stack, I find a solution :).
So, if there's some performance issue or other you may see by looking at my code, do not hesitate to correct me. I just found that this solution solved my problem.
So within my Navigation.js file, I just passed the navigation and route objects to make them usable thanks to the props into my classes, like this :
function App() {
return(
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home"
component={Home}
options={({route, navigation}) => (
{headerTitle: 'Home Page',
route: {route},
navigation: {navigation}}
)}
/>
</Stack.Navigator>
</NavigatorContainer>
)}
then within my classes I just call to this.props.navigation or this.props.route and gather form these objects what I need.
Other thing is that, for those who would use this code to build something similar, I also had to change the way I display the header button.
I do not use the static navigationOptions = () => {} anymore. I just add directly the navigation.setOptions piece of code within the ComponentDidMount function like this:
navigation.setOptions({
headerRight: () => <TouchableOpacity style={styles.settings_touchable_headerrightbutton}
onPress={() => route.params.goToSettings()}>
<Image style={styles.settings_image}
source={require('../assets/ic_settings.png')} />
</TouchableOpacity>
})
I have to do it this way since I'm using a function declared in my class, so I have to bind it in the constructor like this this._goToSettings = this._goToSettings.bind(this) and then add it to the navigation.setParams function.
When navigation.setOptions code is written inside componentDidMount add this.props before navigation and route keyword. Below is the code snippet that worked for me.
this.props.navigation.setOptions({
headerRight: () => <TouchableOpacity style={styles.settings_touchable_headerrightbutton}
onPress={() => this.props.route.params.goToSettings()}>
<Image style={styles.settings_image}
source={require('../assets/ic_settings.png')} />
</TouchableOpacity>
})

How do facebook & instagram update the likes count?

I'm facing an issue with state variables, this.setState({}) method updating the whole page while updating the like count on the card, but Facebook & Instagram are also using the same technology(if I'm not wrong), react native, I wonder how are they doing it.
When clicking a card in my FB feed, it is just updating the count, not the page. But in my program, its updating the whole page. I mean it is re-rendering the page while updating state variables.
Anybody know how to do it?
Thanks
Edits
This is exactly my problem, please see this video, all card is refreshing while clicking a heart.
import Icon from "react-native-vector-icons/MaterialIcons";
...
class GridViewClass extends Component {
...
_renderRow(item, sec, i) {
let addToFavourites = true;
let iconColor = "white";
for(const i in this.props.favoriteTopics){
if(item.topicName === this.props.favoriteTopics[i].topicName){
addToFavourites = false;
iconColor = "red";
}
}
// console.log("item values",item.topicName,item.topicDescription);
return (
<View key={"gridItemContainer_"+item.topicName+this.props.parentKey} style={styles.gridItem}>
<View key={"viewGrid_" + item.topicName+this.props.parentKey} style={styles.gridContainer}>
<TouchableWithoutFeedback key={"touch_" + item.topicName+this.props.parentKey} onPress={() => this.props.openSubCat(item.topicId, item.topicName)}>
<View key={"touchableContainer"+item.topicId+this.props.parentKey}>
<ProgressiveImage imageKey={"imageGrid_" + item.topicName+this.props.parentKey} source={{ uri: item.imageurl }} resizeMode={'stretch'} thumbnailresizeMode={'cover'} thumbnail={require("../../images/placeholder.png")} style={{ width: 170, height: 90, padding: 4, alignSelf: 'center' }} />
<View key={"textContainer"+item.topicId+this.props.parentKey} style={styles.textcontainer}>
<Text style={styles.catname}>{item.topicName}</Text>
<Text style={styles.description}>{item.topicDescription}</Text>
</View>
</View>
</TouchableWithoutFeedback>
<Icon key={"iconKey"+item.topicName+this.props.parentKey} name="favorite" ref={(ref)=>this.storeRowRef(ref)} size={30} color={iconColor} onPress={(event) => addToFavourites?this.addToMyTopics(event,item.topicName):this.removeFromMyTopics(event,item.topicName)}/>
</View>
</View>
)
}
}