constructor(){
super()
this.state = {
make :[]
}
}
componentWillMount(){
fetch('http://link.com', {
method: 'GET',
}).then((response) => response.json())
.then((responseJson) => {
if(responseJson.message === "List of Years"){
var length = responseJson.result.length.toString();
let newarray=[];
for(var i = 0 ; i < length ; i++){
// newarray.push(responseJson.result[i].Makes.year_name.toString());
this.setState({
make: [...this.state.make, responseJson.result[i].Makes.year_name]
});
}
//this.setState({make : newarray})
}
}
).catch((error) => {
console.error(error);
});
}
<Picker
mode="dropdown"
selectedValue={this.state.selected}
onValueChange={(value) => this.setState({selected: value})}>
{this.state.make.map((item, index) => {
return (<Item label={item} value={index}/>)
})}
</Picker>
I made a state named make in construtor and then in componentWillMount() function i fetched data from server and then it set state to make array.But it looks like there is problem with my code.It throws error:
TypeError:undefined is not an object(evaluating 'child.props.value')
I also tried with but problem remains.What i am doing wrong here?
Related
I am trying to get data from a endpoint and then output this data, I can successfully get my data fetched and display it immediately using
fetch(strURL)
.then(res => res.json())
.then((result) => {
console.log("grabed data "+ JSON.stringify(result));
But whenever I try to set the data to my State variable response it fails to do so resulting in an undefined variable. I am really confused why this is occurring as I have another screen that fetches a the same endpoint but it doesn't seem to save to the state variable.
This is the data which is returned:
[{"act_id":"1","act_name":"A bush adventure trail ride in the blue mountains","cat_sub_category":"Free riding","bus_name":"Ditch the road"},{"act_id":"2","act_name":"Paddock riding in the ditch","cat_sub_category":"stable riding","bus_name":"Hallam horses"}]
This is the working screen which fetches the data above
function ActivityDemo(props) {
let [isLoading, setIsLoading] = useState(true);
let [error,setError] = useState();
let [response,setResponse] = useState();
useEffect(() =>{
console.log("fetch activities");
fetch("https://domain/api/activities.php")
.then(res => res.json())
.then((result) => {
console.log("grabed data "+ result);
setIsLoading(false);
setResponse(result);
},
(error) => {
setIsLoading(true);
setError(error);
console.error("error ")
})
}, []);
//What renders
const renderItem = ({item}) => (
<ActivityWidget item={item} ></ActivityWidget>
);
//determines what is displayed
const getContent = (navigation) => {
if (isLoading == true){
return <ActivityIndicator size="large"></ActivityIndicator>
}
if(error == true){
return <Text>{error}</Text>
}
if(isLoading ==false){
console.log(response);
return (
<FlatList
data={response}
renderItem={renderItem}
keyExtractor={item => item.act_id}
/>
);
}
}
return(
<View style={[ContainerStyle.Center]}>
{getContent()}
</View>
);
}
This snippet is from the screen which doesn't work
function ActivityDetails({route},props) {
//get the Route variables
const {actId} = route.params;
let [isLoading, setIsLoading] = useState(true);
let [error, setError] = useState();
let [response, setResponse] = useState();
let strURL = "https://domain/api/detailedActivity.php?actId="+actId;
useEffect(() =>{
console.log("fetch detailed data!");
console.log(strURL);
fetch("https://domain/api/activities.php")
.then(res => res.json())
.then((result) => {
console.log("grabed data "+ JSON.stringify(result));
setIsLoading(false);
setResponse(result);
},
(error) => {
setIsLoading(true);
setError(error);
console.error("error "+ error)
})
}, []);
//determines what is displayed
const getContent = () => {
if (isLoading == true){
return <ActivityIndicator size="large"></ActivityIndicator>;
}
if(isLoading == false){
console.log("Load response Data " +response);
return(
<View style={[ContainerStyle.Container]} >
<Text>{"Name: "+response[0].act_name}</Text>
<Text>{"Description: " +response[0].act_description}</Text>
<Text>{"Bussiness: "+response[0].act_name}</Text>
<Text>{"Category: "+response[0].act_name}</Text>
</View>
);
}
if (error == true){
return <Text>{error}</Text>
}
}
return(
<View style={[ContainerStyle.Center]}>
{getContent()}
</View>
);
}
This is the console logs
LOG fetch activities
LOG grabed data [object Object],[object Object]
LOG undefined
LOG [{"act_id": "1", "act_name": "A bush adventure trail ride in the blue mountains", "bus_name": "Ditch the road", "cat_sub_category": "Free riding"}, {"act_id": "2", "act_name": "Paddock riding in the ditch", "bus_name": "Hallam horses", "cat_sub_category": "stable riding"}]
LOG fetch detailed data!
LOG https://domain/api/detailedActivity.php?actId=2
LOG grabed data [{"act_id":"1","act_name":"A bush adventure trail ride in the blue mountains","cat_sub_category":"Free riding","bus_name":"Ditch the road"},{"act_id":"2","act_name":"Paddock riding in the ditch","cat_sub_category":"stable riding","bus_name":"Hallam horses"}]
LOG Load response Data undefined
LOG Load response Data undefined
I'm not sure why this is not working If someone could tell me what I am doing wrong? Is it to do with the way I am setting state?
Thank you,
Andrew
edit:
I've hidden the endpoints domain
Try this way. Create response state like below.
const [response,setResponse] = useState([]);
then assign value like below
setResponse([...result]);
I have fixed the issue by converting my functions to classes and formatting it with a ComponentDidMount.
class ActivityInfo extends Component {
state = { response : [], isLoading : true};
componentDidMount(){
const {navigation, route}=this.props
const { actId } = route.params;
console.log(actId);
const res = fetch("https://domain/api/detailedActivity.php?actId="+ actId)
.then(res => res.json())
.then((result) => {
console.log("grabbed data "+ result);
this.setState({isLoading:false,response:result});
},
(error) => {
setIsLoading(true);
setError(error);
console.error("error ")
})
console.log(this.state.response)
}
render(){
if(this.state.isLoading == true){
return(<ActivityIndicator style={{alignSelf:"center"}} size="large"></ActivityIndicator>)
}
else{
return(
<View style={[ContainerStyle.Container]} >
<Text>{"Name: "+this.state.response[0].act_name}</Text>
<Text>{"Description: " +this.state.response[0].act_description}</Text>
<Text>{"Bussiness: "+this.state.response[0].bus_name}</Text>
<Text>{"Category: "+this.state.response[0].act_id}</Text>
</View>
);
}
}
}
I had been developing my app for Web, and it has been working properly. However, when I ran the same app within Expo / Android, I got this error. Hard to know what it is about from the description.
This is the full error message:
Cannot add a child that doesn't have a YogaNode to a parent without a measure function! (Trying to add a '[RCTVirtualText 507]' to a '[RCTView 509]')
Do you know what it could possibly be?
This seems to be the js file that is triggering it:
...
export class SubjectListAssignScreen extends React.Component {
state = {
subjectList: [],
subListLoading: true,
};
constructor(props) {
super(props);
};
scrollDimensions = [{
width: Math.round(Dimensions.get('window').width - 20),
maxHeight: Math.round(Dimensions.get('window').height - 200)
}];
...
_getSubjects = async(text) => {
try {
await this.setState({ subListLoading: true });
let lQueryRes = await API.graphql(graphqlOperation(cqueries.listSubjectsCustom, {}));
await console.log('==> Subjects Query');
await console.log(lQueryRes);
await this.setState({ subjectList: lQueryRes.data.listSubjects.items });
await this.setState({ subListLoading: false });
}
catch (e) {
console.log("==> DB Error");
console.log(e);
await this.setState({ subListLoading: false });
};
};
...
_subjectItems = (value) => {
console.log(value.desc);
let lnum = (typeof value["num"] !== 'undefined') ? value["num"].toString() : null;
let desc = value["desc"].toString();
let lastName = (typeof value["users"][0] !== 'undefined') ? value["users"][0]["lastname"].toString() : null;
let ltype = value["type"].toString();
return (
<DataTable.Row onPress={() => {
this.props.navigation.navigate("UserListScreen", {pnum: lnum, ptype: ltype});
}}>
<DataTable.Cell>
{this._getTypeIcon(ltype)}
</DataTable.Cell>
<DataTable.Cell>
<Text>{desc}</Text>
</DataTable.Cell>
<DataTable.Cell>
<Text>{ lastName }</Text>
</DataTable.Cell>
</DataTable.Row>
);
};
async componentDidMount() {
try {
await this._getSubjects();
}
catch (e) {
console.log("==> componentDidMount error");
console.log(e);
};
};
isCloseToBottom = ({ layoutMeasurement, contentOffset, contentSize }) => {
const paddingToBottom = 20;
return layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom;
};
fetchMore = () => {
};
render() {
let sDimensions = this.scrollDimensions;
return (
<View style={{flex:20, margin:4, flexDirection:"column", justifyContent:"flex-start"}}>
<Title style={{flex:1}}>Lista de Demandas</Title>
<SafeAreaView style={[{flex:19, }, sDimensions]}>
<ScrollView
contentContainerStyle={{}}
onScroll={({nativeEvent}) => {
if (this.isCloseToBottom(nativeEvent)) {
this.fetchMore();
}}}
>
<DataTable>
<DataTable.Header>
<DataTable.Title>Type</DataTable.Title>
<DataTable.Title>Subj</DataTable.Title>
<DataTable.Title>Resp.</DataTable.Title>
</DataTable.Header>
{ !this.state.subListLoading ?
<FlatList
data={this.state.subjectList}
renderItem={({item})=>this._subjectItems(item)}
keyExtractor={item => item.desc}
/>
:
<ActivityIndicator />
}
</DataTable>
</ScrollView>
</SafeAreaView>
</View>
)
}
}
Using Expo 37, React Native paper and AWS Amplify.
As I had such a hard time trying to find which components were not compatible, I simply dropped my full development environment, create a clean one and pulled the latest commit again, checking all components version by version and making sure all of them were at the -g version. The error has stopped after that.
I implement a very simple list that calls a server that returns a page containing books.Each book has a title, author, id, numberOfPages, and price). I use a Flat List in order to have infinite scrolling and it does its job very well two times in a row (it loads the first three pages) but later it doesn't trigger the handler anymore.
Initially it worked very well by fetching all available pages, but it stopped working properly after I added that extra check in local storage. If a page is available in local storage and it has been there no longer than 5 seconds I don't fetch the data from the server, instead I use the page that is cached. Of course, if there is no available page or it is too old I fetch it from the server and after I save it in local storage.(Something went wrong after adding this behavior related to local storage.)
Here is my component:
export class BooksList extends Component {
constructor(props) {
super(props);
this.state = {
pageNumber: 0
};
}
async storePage(page, currentTime) {
try {
page.currentTime = currentTime;
await AsyncStorage.setItem(`page${page.page}`, JSON.stringify(page));
} catch (error) {
console.log(error);
}
}
subscribeToStore = () => {
const { store } = this.props;
this.unsubsribe = store.subscribe(() => {
try {
const { isLoading, page, issue } = store.getState().books;
if (!issue && !isLoading && page) {
this.setState({
isLoading,
books: (this.state.books ?
this.state.books.concat(page.content) :
page.content),
issue
}, () => this.storePage(page, new Date()));
}
} catch (error) {
console.log(error);
}
});
}
componentDidMount() {
this.subscribeToStore();
// this.getBooks();
this.loadNextPage();
}
componentWillUnmount() {
this.unsubsribe();
}
loadNextPage = () => {
this.setState({ pageNumber: this.state.pageNumber + 1 },
async () => {
let localPage = await AsyncStorage.getItem(`page${this.state.pageNumber}`);
let pageParsed = JSON.parse(localPage);
if (localPage && (new Date().getTime() - localPage.currentTime) < 5000) {
this.setState({
books: (
this.state.books ?
this.state.books.concat(pageParsed.content) :
page.content),
isLoading: false,
issue: null
});
} else {
const { token, store } = this.props;
store.dispatch(fetchBooks(token, this.state.pageNumber));
}
});
}
render() {
const { isLoading, issue, books } = this.state;
return (
<View style={{ flex: 1 }}>
<ActivityIndicator animating={isLoading} size='large' />
{issue && <Text>issue</Text>}
{books && <FlatList
data={books}
keyExtractor={book => book.id.toString()}
renderItem={this.renderItem}
renderItem={({ item }) => (
<BookView key={item.id} title={item.title} author={item.author}
pagesNumber={item.pagesNumber} />
)}
onEndReachedThreshold={0}
onEndReached={this.loadNextPage}
/>}
</View>
)
}
}
In the beginning the pageNumber available in the state of the component is 0, so the first time when I load the first page from the server it will be incremented before the rest call.
And here is the action fetchBooks(token, pageNumber):
export const fetchBooks = (token, pageNumber) => dispatch => {
dispatch({ type: LOAD_STARTED });
fetch(`${httpApiUrl}/books?pageNumber=${pageNumber}`, {
headers: {
'Authorization': token
}
})
.then(page => page.json())
.then(pageJson => dispatch({ type: LOAD_SUCCEDED, payload: pageJson }))
.catch(issue => dispatch({ type: LOAD_FAILED, issue }));
}
Thank you!
my problem is quite simple but I'm new to react native dev. I'd like to save multiple elements with AsyncStorage (I'm using react-native-simple-store
a library that works like a wrapper but it's same logic) I want display all items for a key in a list , my code look like this:
constructor(props) {
super(props)
this.state = {
UserInput: "",
}
}
SaveValue = () => {
store.push('Favorites', this.state.UserInput)
Keyboard.dismiss()
};
FetchValue = () => {
store.get('Favorites').then((value) => {
this.setState({
favs: value
});
}).done();
};
Same thing with AsynStorage, it just update the item which is not my goal, I'd like to add a new one
SaveValue = () => {
AsyncStorage.setItem("Favorites", this.state.UserInput);
Keyboard.dismiss()
};
FetchValue = () => {
AsyncStorage.getItem("Favorites").then((value) => {
this.setState({
favs: value
});
}).done();
};
This part is my view where I try to display data, you can also see that I use a text input and two buttons one to save and the other to display an array of items stored
render() {
return (
<View>
<TextInput
onChangeText={(UserInput) => this.setState({UserInput})}
placeholder= "Type something"
value={this.state.UserInput} />
<TouchableOpacity
onPress={this.SaveValue}>
<Text>Save</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.FetchValue}>
<Text>Fetch</Text>
</TouchableOpacity>
<Text>{this.state.favs}</Text>
</View>
);
}
At this point I can see only one item, I tried to figure it out and saw that I have to use another method called push but when I changed save by push it throw me an error
Unhandled Promise Rejection : Existing value for key "Favorites" must be of type null or array, revived string.
Thanks!
it will work :)
renderFavorites = () => {
AsyncStorage.getItem("Favorites").then((favs) => {
favs.map((fav) => {
return (<Text> {fav} </Text>);
});
});
}
render() {
return (
<View>
<TextInput
onChangeText={(UserInput) => this.setState({UserInput})}
placeholder= "Type something"
value={this.state.UserInput} />
<TouchableOpacity
onPress={this.SaveValue}>
<Text>Save</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.FetchValue}>
<Text>Fetch</Text>
</TouchableOpacity>
{this.renderFavorites()}
</View>
);
}
Solution using JSON:
SaveValue = () => {
const newFavs = [...this.state.favs, this.state.UserInput];
this.setState({ favs: newFavs, UserInput: '' }, () => {
AsyncStorage.setItem("Favorites", JSON.stringify(this.state.favs));
Keyboard.dismiss()
});
};
FetchValue = () => {
AsyncStorage.getItem("Favorites").then((value) => {
this.setState({
favs: JSON.parse(value)
});
}).done();
};
I'm using https://github.com/f111fei/react-native-banner-carousel/
It works fined with hardcoded images path.
But this error happened if my images array is empty. It will show error as this image
I guess it caused by empty array (please correct me if im wrong). The state.carousels yet to loading to state when it render.
How can I make it asynchronous, so it can load the images dynamically.
So this is my code.
Dashboard.js
componentWillMount(){
this.props.carouselFetch();
}
renderPage(image, index) {
return (
<View key={index}>
<ImageFluid
source={{ uri: image }}
originalWidth={ 2500 }
originalHeight= { 1000 }
/>
</View>
);
}
render(){
const images = this.props.carousels;
return(
......
<Carousel
autoplay
autoplayTimeout={5000}
loop
index={0}
showsPageIndicator={ false }
pageSize={BannerWidth}
>
{ images.map((image, index) => this.renderPage(image, index))}
</Carousel>
......
);
}
const mapStateToProps = (state) => {
const carousels = state.carousel;
return { carousels };
};
CarouselActions.js
export const carouselFetch = () => {
return (dispatch) => {
fetch('API json')
.then((response) => response.json())
.then((response) => {
if (response.Status === 'Fail') {
return Promise.reject(response)
}
return response
})
.then(carousels => {
carouselFetchSuccess(dispatch, carousels);
})
.catch(() => console.log("Error"));
};
};
const carouselFetchSuccess = (dispatch, carousels) => {
dispatch({
type: CAROUSEL_FETCH_SUCCESS,
payload: _.map(carousels.data, i => i.image_path)
});
};
My Sample API json
The package required sample array method
render(){
const images = this.props.carousels;
if (!images || images.length === 0) {
return null;
}
return(
......
<Carousel
autoplay
autoplayTimeout={5000}
loop
index={0}
showsPageIndicator={ false }
pageSize={BannerWidth}
>
{ images.map((image, index) => this.renderPage(image, index))}
</Carousel>
......
);
}
Don't render carousel when the image list length is 0.
First use :
const images = ( this.props.carousels || [] ).map( (image) => ( {
value: carousels .name,
label: carousels .id,
order: carousels .data.
} );
You have a simple array of objects not an nested array, your response it's a simple res.data and not a res.carousel.data, if you use console.log(res) you will see your array, check that.