I try to build react-native app with AsyncStorage with multiGet property. I can sucessfully add stuff to storage, and even display it in debugger console.log but when I want to map through array of data, it constantly shows no result. Does anyone knows where is the problem?
componentDidMount() {
this._getAllData();
}
_getAllData = async () => {
try {
const data = [];
const keys = await AsyncStorage.getAllKeys();
const items = await AsyncStorage.multiGet(keys, (err, stores) => {
stores.map((result, i, store) => {
// let key = store[i][0];
let value = store[i][1];
let parsedValue = JSON.parse(value);
data.push(parsedValue);
});
this.setState({ data });
});
} catch (error) {
this.setState({ error });
}
};
_displayAllData = () => {
// console.log(this.state.data.length);
// console.log(this.state.data);
this.state.data.length &&
this.state.data.map(el => {
return (
<View>
<Text>{el.name}</Text>
<Text>{el.street}</Text>
<Text>{el.postalCode}</Text>
<Text>{el.city}</Text>
<Text>{el.phone}</Text>
<Text>{el.email}</Text>
<Text>{el.nip}</Text>
</View>
);
});
};
and then while rendering my content i try
{this._displayAllData()}
Currently your _displayAllData method is not returning anything. You need to return the map result in order to have some JSX returned by your method.
_displayAllData = () => {
// console.log(this.state.data.length);
// console.log(this.state.data);
return this.state.data.length &&
this.state.data.map(el => {
return (
<View>
<Text>{el.name}</Text>
<Text>{el.street}</Text>
<Text>{el.postalCode}</Text>
<Text>{el.city}</Text>
<Text>{el.phone}</Text>
<Text>{el.email}</Text>
<Text>{el.nip}</Text>
</View>
);
});
};
Related
I am kinda new at react and trying to make two axios get call according to results of first call as you can see in my code. Eventually I am trying to .map the response data in swiper component. However my code is not working properly. The problem is, the data from the first call is displayed on the component properly while the images from the second call are not.
const [picks, setPicks] = useState([]);
const getAllPicks = async () => {
try {
axios.get(".../shoppicks").then(async (response) => {
const responseData = await response.data.result;
for (let i = 0; i < responseData.length; i += 1) {
axios.post(".../getimage", { shopID: response.data.result[i]._id }).then((res) => {
if (res.data.header.arg === "No image found") {
// dummy photo for corrupted responses
responseData[i].imgPath = "#"
} else {
responseData[i].imgPath = res.data
}
})
}
return responseData
}).then((responseData) => {
setPicks(responseData)
console.log(responseData) row 38 logs the data properly
console.log(picks) row 39 logs empty array
})
.catch((error) => console.log(JSON.stringify(error)));
}
catch (error) {
console.log(error)
};
}
useEffect(() => {
getAllPicks();
}, []);
Here where I try .map the data
{picks?.map((pick: IHomePickType) => (
<><SwiperSlide key={pick._id}>
<CardMedia image={pick.imgPath} component="img" />
<div>
<h2>{pick._id}</h2>
</div>
</SwiperSlide></>
))}
Additionally it throws "Each child in a list should have a unique "key" prop." console error even though the picks data has unique keys
I've updated my code according the comments. It is working now.
here is the final code
const [picks, setPicks] = useState([]);
const getAllPicks = async () => {
try {
const response = await axios.get("../shoppicks");
const data = await response.data.result;
for (let i = 0; i < data.length; i += 1) {
const imgResponse = await axios.post("../getimage", { shopID: data[i]._id });
if (imgResponse.data.header.arg === "No image found") {
// dummy photo for corrupted responses
data[i].imgPath = "#"
} else {
data[i].imgPath = imgResponse.data.result.imgPath
}
}
setPicks(data)
}
catch (error) {
console.log(error)
};
}
component =>
{picks?.map((pick: IHomePickType) => (
<SwiperSlide key={pick._id}>
<CardMedia image={pick.imgPath} component="img" />
<div>
<h2>{pick._id}</h2>
</div>
</SwiperSlide>
))}
Thanks
I am attempting to develop a React app which makes a call to a database to load a set of pages to a board to build a drag and drop decision tree.
I am only just starting out with React, so keen to hear about anything I'm doing wrong here.
Using 'useEffect' the pageTree function will load the pages up on the first load and on every refresh, however the pages state returns with an empty array instead of the current pages.
Strangely enough the pages all show up on the board with the pages.map function which works on the pages state... (which returns as empty on console.log...)
If I add a page to the array it saves the change to the database, but then will only show the new page on the board. You will then have to refresh to see the new set of pages (including the added page).
Calls to add or delete a page are called by the layout menu buttons in the parent component.
Console after refresh
Additionally, if I move a page, the state will console OK:
Page state in console after moving a page. DB call and state update works OK
function PageTree({AddNewPageFunc}) {
const [pages, setPages] = useState([]);
const movePage = useCallback((droppedPage) => {
const updatedPages = pages.map(page => droppedPage._id == page._id ? droppedPage : page);
setPages(updatedPages);
}, [pages]);
const [{isOver}, drop] = useDrop(() => ({
accept: ItemTypes.PAGECARD,
drop(page, monitor) {
const delta = monitor.getDifferenceFromInitialOffset();
let x = Math.round(page.x + delta.x);
let y = Math.round(page.y + delta.y);
page.x = x;
page.y = y;
movePage(page);
setNewPagePosition(page);
return undefined;
},
}), [movePage]);
const setNewPagePosition = async (pageDetails) => {
console.log("function called to update page position");
Api.withToken().post('/pageupdate/'+pageDetails._id,
pageDetails
).then(function (response) {
console.log("moved page: ",response.data)
}).catch(function (error) {
//console.log(error);
});
}
React.useEffect(() => {
AddNewPageFunc.current = AddNewPage
}, [])
const AddNewPage = useCallback(() => {
console.log("calling add new page function")
console.log("the pages before the API call are ",pages)
Api.withToken().post('/addblankpage/'
).then(function (response) {
console.log("produced: ",response.data);
setPages(pages.concat(response.data))
console.log("the pages after updating state are: ",pages)
}).catch(function (error) {
//console.log(error);
});
}, [pages]);
const handleDelete = async (id) => {
Api.withToken().post('/deletepages/'+id
).then(function (response) {
let index = pages.findIndex(function(item){
return item.id === response.data._id;
});
const PageRemoved = pages.splice(index, 1);
setPages(PageRemoved);
}).catch(function (error) {
//console.log(error);
});
}
useEffect(() => {
Api.withToken().get('/pages/')
.then(res => {
setPages(res.data);
console.log('res data ',res.data);
console.log('pages ',pages);
})
}, []);
return (
<div ref={drop} style={styles}>
{pages.map((page) => (<PageCard page={page} id={page._id} key={page._id} handleDelete={() => handleDelete(page._id)} handleMaximise={() => handleMaximise(page)} handleCopy={() => handleCopy(page)}/>))}
</div>
)
}
export default PageTree;
As Danielprabhakaran pointed out, the issue was the callback in React.useEffect. On adding a new page it needed to send the updated page state back to the parent component.
Using console.log on a state after an API call seems to be fraught, even if using .then(console.log(state)
function PageTree({AddNewPageFunc}) {
const [pages, setPages] = useState([]);
const movePage = useCallback((droppedPage) => {
const updatedPages = pages.map(page => droppedPage._id == page._id ? droppedPage : page);
console.log("updated pages ",updatedPages);
setPages(updatedPages);
console.log("set pages ",pages);
}, [pages]);
const [{isOver}, drop] = useDrop(() => ({
accept: ItemTypes.PAGECARD,
drop(page, monitor) {
const delta = monitor.getDifferenceFromInitialOffset();
let x = Math.round(page.x + delta.x);
let y = Math.round(page.y + delta.y);
page.x = x;
page.y = y;
movePage(page);
setNewPagePosition(page);
return undefined;
},
}), [movePage]);
const setNewPagePosition = async (pageDetails) => {
console.log("function called to update page position");
Api.withToken().post('/pageupdate/'+pageDetails._id,
pageDetails
).then(function (response) {
console.log("?worked ",response)
}).catch(function (error) {
//console.log(error);
});
}
React.useEffect(() => {
AddNewPageFunc.current = AddNewPage
}, [pages])
const AddNewPage = useCallback(() => {
console.log("calling add new page function")
console.log("the pages before the API call are ",pages)
Api.withToken().post('/addblankpage/'
).then(function (response) {
console.log("produced: ",response.data);
setPages(pages.concat(response.data))
console.log("the pages after updating state are: ",pages)
}).catch(function (error) {
//console.log(error);
});
}, [pages]);
const handleDeletedCallback = (deletedIndex) => {
console.log("delete callback fired")
setPages(pages.splice(deletedIndex, 1));
}
useEffect(() => {
Api.withToken().get('/pages/') //can add in a prop to return only a given tree once the app gets bigger
.then(res => {
setPages(res.data);
console.log('res data ',res.data);
console.log('pages ',pages);
})
}, []);
return (
<div ref={drop} style={styles}>
{pages.map((page, index) => (<PageCard page={page} id={page._id} key={page._id} index={index} deleteCallback={handleDeletedCallback} handleMaximise={() => handleMaximise(page)} handleCopy={() => handleCopy(page)}/>))}
</div>
)
}
export default PageTree;
I'm using Axios to get data from an API.
I want to loop through all the items in a feed fetch with Axios using map function and get there title. But I don't know how to map it because my feed is structure like items[0].title, items[1].title...
const URL = 'https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fvnexpress.net%2Frss%2Fthe-gioi.rss';
let content = null;
const [feed, setFeed] = useState(null);
useEffect(() => {
axios.get(URL).then((response) => {
setFeed(response.data);
});
}, [URL]);
if(feed) {
/// To get title of first item: content = <Text>{feed.items[0].title}
content =
feed.map(f => {
return <Text>{f.items[???].title}</Text> /// How to loop through all the items[0].title, items[1].title, items[2].title ?
})
}
return (<View>{content}</View>);
EDIT;
If you got array of Feed
const URL = 'https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fvnexpress.net%2Frss%2Fthe-gioi.rss';
let content = null;
const [feed, setFeed] = useState(null);
useEffect(() => {
axios.get(URL).then((response) => {
setFeed(response.data);
});
}, [URL]);
if(feed) {
/// To get title of first item: content = <Text>{feed.items[0].title}
content = () => {
feed.map((f) => {
return (
<View>
{feed.items.map((item) => {
return <Text>{item.title}</Text>;
})}
</View>
);
});
};
}
return (<View>{content && content()}</View>);
const content = () => {
feeds.map((f) => {
return (
<View>
{feeds.items.map((item) => {
return <Text>{item.title}</Text>;
})}
</View>
);
});
};
If always you get a single Feed
content =
(<View>{feed.items.map(item)=> {
return<Text>{item.title}</Text>
}}</View>)
I am trying to set the state of a variable that is initially populated from an API call...
getInServiceVenues = () =>{
this.setState({ loading: true });
let bodyInService = [];
let iterationInService = 0;
let RequestingNetworkOperatorList = [];
axios.post( '/propertymanagement/listVenues', bodyInService,
{
headers: {}
})
.then( response => {
if (this._isMounted) {
this.setState({loading: false});
this.setState({venues: []});
const venuesInService = response.data.InServiceVenueList;
let venueIdInService = null;
let updatedVenuesInService = [];
bodyInService.push(venuesInService);
bodyInService.forEach(val=>{
venueIdInService = Object.keys(bodyInService[0]);
//console.log(venueId);
})
if(this.state.venuesInService!==[]){
this.setState({venuesInService:[]});
}
venueIdInService.forEach(val=>{
updatedVenuesInService = bodyInService.map(venueInService => {
return {
...venueInService[venueIdInService[iterationInService]],
iterationInService,
RequestingNetworkOperatorList
}
});
this.setState({
venuesInService:[...this.state.venuesInService, updatedVenuesInService]
});
iterationInService = iterationInService + 1;
})
}} )
.catch(error => {
console.log(error);
this.setState({error: true});
});
}
On the click of a button I call this function...
postSelectedHandler = (venues) => {
this.setState({newVenue: true}, () => {
console.log(this.state.newVenue);
});
this.getInServiceVenues();
var event = new Event('input', { bubbles: true });
this.search_venue.dispatchEvent(event);
this.filterList(event);
}
I can only see the updated state if I were to change an input box's value which is why I have the event variable in my function (trying to do an onChange automatically). Any help would be appreciated.
Edited with the render method attached...
render () {
//console.log(this.state.allVenues);
const { isBoxVisible } = this.state;
const {loading } = this.state;
let inServiceVenues = <Alert variant="danger">Something went wrong!</Alert>;
let preAuthVenues = <Alert variant="danger">Something went wrong!</Alert>;
let waitingAuthVenues = <Alert variant="danger">Something went wrong!</Alert>;
let availableVenues = <Alert variant="danger">Something went wrong!</Alert>;
if (!this.state.error) {
inServiceVenues = this.state.filterVenuesInService.map(venueInService => {
return <Venue
key={venueInService[0].iteration}
city={venueInService[0].City}
VenueName={venueInService[0].VenueName}
NetworkOperatorID={venueInService[0].NetworkOperatorID}
ConnectedKeyPools={venueInService[0].connectedKeyPoolList}
clicked={() => this.postSelectedHandler(venueInService.id)} />;
});
preAuthVenues = this.state.filterVenuesPreAuth.map(venuePreAuth => {
return <PreAuthVenues
key={venuePreAuth[0].iteration}
city={venuePreAuth[0].City}
VenueName={venuePreAuth[0].VenueName}
NetworkOperatorID={venuePreAuth[0].NetworkOperatorID}
ConnectedKeyPools={venuePreAuth[0].connectedKeyPoolList}
clicked={() => this.postSelectedHandler(venuePreAuth.id)} />;
});
waitingAuthVenues = this.state.filterVenuesWaiting.map(venueWaitingAuth => {
//console.log(venueWaitingAuth[0].RequestingNetworkOperatorList[0]);
let connectedKeyPoolListNewLine;
if(venueWaitingAuth[0].connectedKeyPoolList!=undefined){
connectedKeyPoolListNewLine = JSON.stringify(venueWaitingAuth[0].connectedKeyPoolList, "<p>").replace(/[[\]"']+/g,'').replace(/,+/g, '\n');
//console.log(connectedKeyPoolListNewLine.replace(/\n,+/g, ''));
}else{
connectedKeyPoolListNewLine = '';
}
return <WaitingAuthVenues
key={venueWaitingAuth[0].iterationWaitingAuth}
city={venueWaitingAuth[0].City}
VenueName={venueWaitingAuth[0].VenueName}
VenueID={venueWaitingAuth[0].awaitingAuthVenueID}
connectedKeyPoolList={connectedKeyPoolListNewLine}
RequestedOperatorList={Object.keys(venueWaitingAuth[0].RequestingNetworkOperatorList)}
AwaitingAuthorizationKeyPool={venueWaitingAuth[0].AwaitingAuthorizationFromKeyPoolOwnerKeyPoolList}
filteredVenuesInService={inServiceVenues}
clicked={() => this.postSelectedHandler(venueWaitingAuth.id)} />;
});
availableVenues = this.state.filterVenuesAvailable.map(venue => {
let connectedKeyPoolListNewLine;
if(venue[0].connectedKeyPoolList!=undefined){
connectedKeyPoolListNewLine = JSON.stringify(venue[0].connectedKeyPoolList, "<p>").replace(/[[\]"']+/g,'').replace(/,+/g, '\n');
//console.log(connectedKeyPoolListNewLine.replace(/\n,+/g, ''));
}else{
connectedKeyPoolListNewLine = '';
}
//console.log(connectedKeyPoolList);
return <AvailableVenues
key={venue[0].iteration}
city={venue[0].City}
VenueName={venue[0].VenueName}
connectedKeyPoolList={connectedKeyPoolListNewLine}
id={venue[0].availableVenueID}
clicked={() => this.postSelectedHandler(availableVenues.id)}
submitted={this.forceUpdateHandler}
getNewData={this.getAvailableVenues}/>;
});
//console.log(this.state.venues[0]);
}
The number would increased by 1 when I pushed the button.
However, after refreshing the screen, the number shows 「0」.
I want to show the number where it left off before refreshing.
Where should I fix to store the value in AsyncStorege correctly?
Could you give some advice please?
export default class ApplauseButton extends Component {
constructor(props) {
super(props);
this.state = {
applause: 0,
};
}
componentDidMount = () => {
const applauseCount = parseInt(AsyncStorage.getItem('applause'),10);
this.setState({applaused:applauseCount});
};
handlClick() {
const countapplause = this.state.applause + 1;
AsyncStorage.setItem('applause', countapplause.toString()).then(() => {
this.setState({ applause: this.state.applause + 1});
});
};
render() {
return (
<View style={styles.container}>
<Button title="👋"
onPress={() => {
this.handlClick()
}} />
<Text style={styles.count}>
{this.state.applause}/
</Text>
</View>
);
}
}
I suppose there are two things you should change:
1.Set the state when you get the count from the AsyncStorage.
2.you are setting the previous value in AsyncStorage instead store the incremented value.
componentDidMount = () => {
getcount();
};
getcount = async () => {
let count = '';
try {
count = await AsyncStorage.getItem('applause') || '0';
count = parseInt(count,10);
this.setState({applause:count})
} catch (error) {
// Error retrieving data
console.log(error.message);
}
}
handlClick= async ()=> {
const count = this.state.applause + 1;
try{
await AsyncStorage.setItem('applause', count.toString());
this.setState({ applause: count});
}
catch(error){
console.log(error.message);
}
};