fetching values from server for multiselect picker react native - react-native

I tried fetching values from server for multi select picker component from the package https://github.com/toystars/react-native-multiple-select. But i get an error message: TypeError: null is not an object(evaluating this.state.LangKnown).
Please Kindly help.Thank u
My JSON values
{
"MFBasic": {
"SkinTones": "DARK,FAIR,VFAIR",
"Build": "SLIM,ATHLETIC,PLUMPY",
"Gender": "F,M,T",
"Genre": "ACTION,COMEDY,DRAMA",
"Languages": "ENG,HINDI,TAM",
"MediaModes": "ADS,MOVIES,SHORTFILMS",
"Tags": "BIKES,HOME,JEWELLARY"
},
"Result": "Successfully Loaded MF Basic Details",
"Code": 100
}
import React, {Component} from "react";
import { Text, View, StyleSheet, Picker, Alert } from "react-native";
import MultiSelect from "react-native-multiple-select";
export default class App extends React.Component {
state = {
LangPickerValueHolder: [],
LangKnown: []
}
componentDidMount () {
fetch('https://movieworld.sramaswamy.com/GetMFBasicDetails.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(response => response.json())
.then(responseJson => {
let langString = responseJson.MFBasic.Languages;
let langArray = langString.split(',');
this.setState({
LangPickerValueHolder: langArray
});
}).catch(error => {
console.error(error);
});
}
render () {
return (
<View style={styles.itemContainer}>
{<MultiSelect
ref={(component) => { this.multiSelect = component; }}
onSelectedItemsChange={(value) =>
this.setState({ LangKnown: value })
}
selectedItems={this.state.LangKnown}
onChangeInput={ (text) => console.log(text)}
displayKey = ''name
submitButtonText="Submit">
{this.state.LangPickerValueHolder.map((item, key) => (
<MultiSelect.Item item = {item} uniqueKey = {key}/>
))}
</MultiSelect>}
</View>
);
}
}

You've made a good attempt at how to set up the MultiSelect however there are a couple of issues that need to be resolved.
If you look at the dependency the data that should be passed to it should be an array of objects. The example gives the object as { id: '92iijs7yta', name: 'Ondo' } We can easily transform your data from an array of strings into an array of objects that match the example.
let LangPickerValueHolder = langArray.map((name, id) => { return { name, id }; });
Using a map we can convert the array.
This would make your componentDidMount look like the following:
componentDidMount () {
fetch('https://movieworld.sramaswamy.com/GetMFBasicDetails.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(response => response.json())
.then(responseJson => {
let langString = responseJson.MFBasic.Languages;
let langArray = langString.split(',');
let LangPickerValueHolder = langArray.map((name, id) => { return { name, id }; }); // <- here we had the mapping function
this.setState({ LangPickerValueHolder }); // <- save the new array of objects into the state
console.log(langArray);
}).catch(error => {
console.error(error);
});
}
Setting up the MultiSelect component requires a few more changes.
Firstly there is no MultiSelect.Item so the map that you are using to populate the MultiSelect won't work. Instead you need to use the items prop to set the items. Next you need to tell the MultiSelect component the correct uniqueKey prop (which in our case will be id) and set the displayKey correctly.
Here is what your render could look like.
render () {
return (
<View style={styles.container}>
<MultiSelect
ref={(component) => { this.multiSelect = component; }}
onSelectedItemsChange={(value) =>
this.setState({ LangKnown: value })
}
uniqueKey="id"
items={this.state.LangPickerValueHolder}
selectedItems={this.state.LangKnown}
onChangeInput={ (text) => console.log(text)}
displayKey = 'name'
submitButtonText="Submit" />
</View>
);
}
Here is it put together in a snack: https://snack.expo.io/#andypandy/multiselect-with-data-from-api
Here is the code from the snack:
import React from 'react';
import { View, StyleSheet } from 'react-native';
import MultiSelect from 'react-native-multiple-select';
export default class App extends React.Component {
// declaring state like this is absolutely fine, it doesn't need to be in a constructor
state = {
LangPickerValueHolder: [],
LangKnown: []
}
componentDidMount () {
fetch('https://movieworld.sramaswamy.com/GetMFBasicDetails.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}).then(response => response.json())
.then(responseJson => {
let langString = responseJson.MFBasic.Languages;
let langArray = langString.split(',');
let LangPickerValueHolder = langArray.map((name, id) => { return { name, id }; });
this.setState({
LangPickerValueHolder
});
console.log(langArray);
}).catch(error => {
console.error(error);
});
}
render () {
return (
<View style={styles.container}>
<MultiSelect
ref={(component) => { this.multiSelect = component; }}
onSelectedItemsChange={(value) =>
this.setState({ LangKnown: value })
}
uniqueKey="id" // <- set the value for the uniqueKey
items={this.state.LangPickerValueHolder} // <- set the items you wish to show
selectedItems={this.state.LangKnown}
onChangeInput={ (text) => console.log(text)}
displayKey = 'name' . // <- fix typo here
submitButtonText="Submit" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: 'white',
padding: 8
}
});

Related

Error: Too many re-renders. React limits the number of renders to prevent an infinite loop React Native with FlatList render

I don't understand why I get this error, when rendering screen I use useSelector to get state from store(I'm using redux) I get data from api and pass it to flatList to render the list, everything is normal but I don't know why
const HistoryScreen = () => {
const { loading, histories } = useSelector((state) => state.historiesList)
useEffect(() => {
if (user) {
dispatch(listHistory())
}
}, [dispatch, user])
return (
<FlatList data={histories} renderItem={({ item, i }) => <HistoryCard key={i} onPress={() => console.warn('cliecked')} post={item} ></HistoryCard>}>
</FlatList >
</View >}</>
)
}
export default HistoryScreen
action:
export const listHistory = (skip = 0, limit = 10) => async (dispatch, getState) => {
try {
dispatch({ type: HISTORY_LIST_REQUEST })
const user = await AsyncStorage.getItem('userInfo')
const userInfo = user ? JSON.parse(user) : null
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const payload = { skip: skip, limit: limit }
const { data } = await axios.post(`${api}/histories/`, payload, config)
dispatch({ type: HISTORY_LIST_SUCCESS, payload: data.data })
console.log(data.data)
} catch (error) {
dispatch({ type: HISTORY_LIST_FAILED, payload: error })
}
}

React Native - fetch to setState returns the old value

I'm trying to update a row in database with API request Post when click in button (cancel or finish).
The value is update correctly in database but when i click button onPress={() => { settersApi('Finish'); gettersApi(); }} in gettersApi() console.log(estado) return the old value from hook "estado".
export default Home = ({navigation}) => {
const [estado, setEstado] = useState([]);
const gettersApi = async () => {
try {
let response = await fetch(
'http://api/getValues', {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
},
}
);
let json = await response.json();
setEstado(json);
console.log(estado);
} catch (error) {
console.error(error);
}
};
useEffect(() => {
gettersApi();
}, []);
const settersApi = async (param) => {
try {
let response = await fetch(
'http://api/setValues', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
},
body: JSON.stringify({
id: estado.id,
estado: param,
})
}
);
let json = await response.json();
} catch (error) {
console.error(error);
}
};
const CButtons = () => {
return (
<View>
<View>
<Button
color='#ffc107'
title="CANCEL"
onPress={() => {
settersApi('Cancel');
gettersApi();
}}
/>
</View>
<View>
<Button
color='#28a745'
title="FINISH"
onPress={() => {
settersApi('Finish');
gettersApi();
}}
/>
</View>
</View>
);
};
return (
<View style={styles.body}>
<CButtons></CButtons>
</View>
);
};
The function from useState that you called setEtado is a async function. You wont see any changes right away after you change it.
Try to watch the variable state and see when it's updated by using useEffect
useEffect(() => {
console.log(estado);
}, [estado]);

How to get id from json react-native-material-dropdown

I have used react-native-material-dropdown in my react native project. I am getting a data from API.
I am sorry, my English is bad.
fetch('xxxx.json', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
}).then((response) => response.json())
.then((responseJson) => {
var count = Object.keys(responseJson.cities).length;
for(var i=0;i<count;i++){
//console.warn(responseJson.cities[i].name) // I need to add
//these names to dropdown
this.state.drop_down_data.push({ value: responseJson.cities[i].name,id:responseJson.cities[i].id });
}
//this.setState({ drop_down_data });
})
.catch((error) => {
console.error(error);
});
and Dropdown code
<Dropdown
label='City'
data={this.state.drop_down_data}
onChangeText={this.onCityChange.bind(this)}
/>
and Change method issue is here
onCityChange(val,ind,data){ fetch('xxxx/'+ cityid +'/towns.json', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
}).then((response) => response.json())
.then((responseJson) => {
this.setState({drop_down_data2: []});
var count = Object.keys(responseJson.towns).length;
for(var i=0;i<count;i++){
//console.warn(responseJson.towns[i].name) // I need to add
//these names to dropdown
//
this.state.drop_down_data2.push({ value: responseJson.towns[i].name,id:responseJson.towns[i].id });
}
//this.setState({ drop_down_data });
})
.catch((error) => {
console.error(error);
});
}
in here i want to city id.value is coming but id not coming or i dont know get to id.
if i can get id, i can a post request for town.
how i can do this?
and some json data
{
"id": 1,
"name": "Adana",
"alpha_2_code": "TR-01"
},
{
"id": 2,
"name": "Adıyaman",
"alpha_2_code": "TR-02"
},
onChangeText Method have 3 parameters (value, index, data)
data = Complete Array
index = Current Item index selected
You can get id by this code
onChangeText = (value, index, data) => {
const cityId = data[index].id;
console.log("cityId", cityId);
};
Complete Sample Code
import React, { Component } from "react";
import { Dropdown } from "react-native-material-dropdown";
const data = [
{
value: "City1",
id: 1
},
{
value: "City2",
id: 2
},
{
value: "City3",
id: 3
}
];
export default class Example extends Component {
onChangeText = (value, index, data) => {
const cityId = data[index].id;
console.log("cityId", cityId);
};
render() {
return (
<Dropdown
label="Favorite Fruit"
data={data}
style={{ marginTop: 50 }}
onChangeText={this.onChangeText}
/>
);
}
}

Why can I not call on state in the render of a component after fetching data using fetch with React Native

Fairly new to React. Really new to react native. I know you should be able to reference state object in render method but when I try I get an error that is undefined. "Cant get variable of undefined" I want to set up a page that details each entry by id and the fetch method returns the details regarding each venue. I console this.state.data[0].venueName above and it logs out but when I try to reference it in the component it says its undefined.
class BreweryDetailScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
componentWillMount() {
this.getBrewDeetsHandler();
}
getBrewDeetsHandler = () => {fetch('api url', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
itemID: this.props.navigation.state.params.id
}),
}) .then(res => res.json())
.then(myJson => {
this.setState({
data: myJson
});
console.log(this.state.data[0].venueName)
})
.catch((error) => {
console.error(error);
});
};
render() {
return (
<Text>{this.state.data[0].venueName}</Text>
);
}
}
You should handle the loading phase!
you can try to define an isLoading: true state which will change to false when data have been loaded!
Also please do NOT make API request in componentWillMount() and use componentDidMount() instead!
look at this:
import React, { Component } from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
class BreweryDetailScreen extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
data: []
};
}
componentDidMount() {
this.getBrewDeetsHandler();
}
getBrewDeetsHandler = () => {
fetch('api url', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
itemID: this.props.navigation.state.params.id
})
})
.then(res => res.json())
.then(myJson => {
this.setState({
isLoading: false,
data: myJson
});
console.log(this.state.data[0].venueName);
})
.catch(error => {
console.error(error);
});
};
render() {
if (this.state.isLoading) {
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}
>
<ActivityIndicator size='large' color='red' />
</View>
);
} else {
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}
>
<Text>{this.state.data[0].venueName}</Text>
</View>
);
}
}
}
export default BreweryDetailScreen;
Few good practices are,
Don't call API in componentWillMount,
componentWillMount() {
this.getBrewDeetsHandler();
}
To call API make use of componentDidMount,
componentDidMount() {
this.getBrewDeetsHandler();
}
API call is async, you won't be able to get data directly after API call because API call will take some time to execute and till that time your component will get render and you will get undefined error for your state.
You can make use of asyn/await for API call,
getBrewDeetsHandler = async () => {
await fetch('api url', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
itemID: this.props.navigation.state.params.id
}),
}) .then(res => res.json())
.then(myJson => {
this.setState({
data: myJson
}, ()=> console.log(this.state.data[0].venueName));//Callback in setState
})
.catch((error) => {
console.error(error);
});
};
After setting state, you won't be able to do console.log with new state value, because setState is also async, make use of callback in setState to console.log data, as I did above.
When you try to use state, do always check if state value exists,
<Text>{this.state.data && this.state.data[0].venueName}</Text>
because setState is an asynchronous operation and you are trying to access to state immediately after setState. please try this one.
this.setState({
data: myJson
}, () => { console.log(this.state.data[0].venueName); });
the second parameter of 'setState' method is a callback function which will be run after changing the state.

Getting Undefined in React native

import React, { Component } from 'react';
import { View, Text } from 'react-native';
class HttpExample extends Component {
state = {
data: ''
}
componentDidMount = () => {
fetch("https://jsonplaceholder.typicode.com/posts/1", { --this is fake url
method: 'POST',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded', // <-- Specifying the Content-Type
}),
body: "param1=value1&param2=value2" // <-- Post parameters
})
.then((response) =>
response.text()
)
.then((responseText) => {
alert(responseText.id);
this.setState({
data: responseText
})
})
.catch((error) => {
console.error(error);
});
}
render() {
return (
<View>
<Text>
{this.state.data.id}
</Text>
</View>
)
}
}
export default HttpExample;
if i use alert(ResponseText)
in alert i am getting o/p but as i tried to have individual value from my object it returns undefined
o/p: "id": "1",
"computeId": "USR00001" in alert
.then((response) => response.text())
to
.then((response) => response.json())
I guess you need json style response.