React fetching parameters from URL - reactjs

I'm new to React and have been using it for couple weeks.
I was wondering how to make my cod work to dynamically get data from url and display it
searchSome() {
var serachValue=
"http://localhost:8005/api?act=search&term=" + this.state.valSearch+ "+";
fetch(serachValue)
.then(data => data.json())
.then(result => {
// console.log(this.state.library);
var object= JSON.stringify(this.state.library);
var stringify = JSON.parse(object);
});
}
The link result in data such as id, name etc.
I need to filter that as the user enters words in the search bar and display it.
display code
const filter = this.state.library.filter(book=> {
return (
book.name.indexOf(this.searchSome()) !== -1 ||
book.description
.indexOf(this.searchSome()) !== -1
);
});
Any help much appreciated!

Try below
searchSome(searchTerm) {
var serachValue=
"http://localhost:8005/api?act=search&term=" + searchTerm + "+";
fetch(serachValue)
.then(data => data.json())
.then(result => {
// Not sure what is your format, but you have to set this data to state
this.setState({ library: result });
});
}
render() {
return (
<View>
<TextInput
onChangeText={(text) => {
// Should debounce the call to `searchSome` to avoid multiple request
this.searchSome(text);
this.setState({ searchValue: text })
}}
text={this.state.searchValue}
/>
<FlatList
data={this.state.library}
/>
</View>
)
}

Related

Pass data of array to react native view

I have a function that fetch the data from backend and map over the data and then add them to array
called events_data
function getvals() {
return fetch('http://**********/users/timetable')
.then((response) => response.json())
.then((output) => {
addData(output, events_data);
})
.catch(error => console.log(error))
}
function addData(data, data2) {
data.map((d) => {
data2.push({
title: d.name,
startTime: genTimeBlock(d.day, d.start_time),
endTime: genTimeBlock(d.day, d.end_time),
location: d.location,
extra_descriptions: [d.extra_descriptions],
});
});
}
So in my app view I want to pass events_data to events props:
<SafeAreaView style={{ flex: 1, padding: 30 }}>
<View style={styles.container}>
<TimeTableView
scrollViewRef={this.scrollViewRef}
events={// events.data will be passed here as array format //}**
pivotTime={8}
pivotDate={this.pivotDate}
numberOfDays={this.numOfDays}
onEventPress={}
headerStyle={styles.headerStyle}
formatDateHeader="dddd"
locale="en"
/>
</View>
</SafeAreaView>
Side note: the timetable view it is a third party package that accept array passed in porp events={} and display its data in timetable format
so here I want to pass events_data array coming from function addData and pass it to events prop in <TimeTableView>
function getvals() {
return fetch('http://**********/users/timetable')
.then((response) => response.json())
.then((output) => {
return addData(output, events_data); //<-- add a return statement.
})
.catch(error => console.log(error))
}
in your class component where you are calling the get Val function.
const data = getvals();
this.setState({ events: data });
then you can use this.state.events in your table.

How can i request remote data after press enter? (mbrn/material-table)

I'm using remote data example from material table, The current behavior
In componentDidMount the data request by default.
any search or sorting make by default another request to get data based on the new query
I can delay the request by providing debounceInterval
What I want to do?
I want when Itype in the global search----> I don't want to get data by default unless I press enter
And here is my render method that will make the table resolves the remote data once it's received the data
<Entity
storeId={storeId}
entityRef={ref => { this.entity = ref; }}
onEntityReceived={data => this.onEntityReceived(data)}
onEntityReceivedError={data => this.onEntityReceivedError(data)}
render={store => (
<React.Fragment>
<If condition={this.exceptionError}>
<Message variant={'warning'} text={this.exceptionError} />
</If>
<MaterialTable
tableRef={ref => this.tableRef = ref}
title={this.title}
data={query => {
this.get(query);
return new Promise(resolve => event.on('data-fetched', resolve));
}}
isLoading={(store.loading && this.exceptionErrorsLoader) || isLoading}
options={this.options}
actions={this.actions}
localization={this.localization}
columns={this.columns}
components={this.components}
icons={this.icons}
detailPanel={this.rowDetailsPanel}
onRowClick={onRowClick}
/>
Here is the code that will handle received data to provide it to the table
onEntityReceived(data) {
this.exceptionErrorsLoader = false;
event.notify('data-fetched', {
page: this.state.pageIndex,
totalCount: data.totalCount,
data,
});
}
This is the get method that will get the data from server
get(query) {
const { oldQuery } = this.state;
const { additionalEntityPayload } = this.props;
const serverSideLink = this.getServerSideLink(query);
this.exceptionErrorsLoader = true;
this.setState({
query,
// ======== In Order To Save FIRST_QUERY (in case we need to refresh old data)
oldQuery: isEmpty(oldQuery) ? query : oldQuery,
pageIndex: query.page,
pageSize: query.pageSize,
}, () => {
if(!isEmpty(additionalEntityPayload)) {
return this.entity.get({
serverSideLink, additionalPayload: additionalEntityPayload });
}
this.entity.get({ serverSideLink });
});
}
The issue is I don't know how to control the search field or other field because they are not exposed
Thanks in Advance.

Increment value in react native

I'm getting data from a payload which has a total number of likes on each post. On the user screen, there's an icon for the user to like a post and what i want to achieve is when the user taps on it, the value show be increased to plus 1 against that particular post
VIEW:
{
posts.map((item, i) => {
return (
<View key={i} style={styles.user}>
<Card>
<ListItem
titleStyle={{ color: '#36c', fontWeight:'500' }}
titleNumberOfLines={2}
hideChevron={false}
roundAvatar
title={item.headline}
avatar={{uri:'https://s3.amazonaws.com/uifaces/faces/twitter/brynn/128.jpg'}}
/>
<Text style={{marginBottom: 10, fontSize:16, color:'#4a4a4a', fontFamily:'HelveticaNeue-Light'}}>
{item.text}
</Text>
<TouchableOpacity style={styles.likeContainer}>
<Text style={{fontSize:14}}>{item.likesCount}{"\n"}</Text>
<Icon
onPress={()=>onLikePost(item)}
name='md-thumbs-up'
type='ionicon'
iconStyle={[(item.isLiked=== true) ? styles.likedColor : styles.unLikedColor]}
/>
</TouchableOpacity>
</Card>
</View>
);
})
}
CONTAINER:
state = {
posts : [],
id: '',
user: ''
}
componentDidMount = () => {
const { navigation } = this.props;
this.setState({
id : navigation.getParam('id'),
user: navigation.getParam('user')
}, ()=> this.getData())
}
getData = () => {
const api = create({
baseURL: 'https://url.com/api',
headers: {'Accept': 'application/json'}
});
api.get('/groups/'+`${this.state.groupID}`+'/posts').then((response) => {
let data = response.data.data
this.setState({ posts: data });
console.log(JSON.stringify(this.state.posts))
})
}
onLikePost = (item) => {
item.likeCount = item.likeCount+1
}
You are storing posts data in state variable so use setState to update it. Use map and check for each post, whenever id (unique property of each post) matches to id of the clicked item, increase its likesCount otherwise return the same data.
Write it like this:
onLikePost = (item) => {
this.setState(prevState => ({
posts: prevState.posts.map(el => el.id === item.id? {...el, likesCount: el.likesCount+1} : el)
}))
}
Update: Put the check before updating the count value and change the isLiked bool also.
onLikePost = (item) => {
this.setState(prevState => ({
posts: prevState.posts.map(el => {
if(el.id === item.id) {
return {
...el,
isLiked: !el.isLiked,
likesCount: !el.isLiked? el.likesCount+1 : el.likesCount-1,
}
}
return el;
})
}))
}
Note: I am assuming each post has a key id unique value, if it doesn't exist then use any other unique property of the each post.
If array sequence is not an issue, you can use item index and use setState to update it.
<Icon
onPress={()=>onLikePost(i)}
...
/>
...
onLikePost = (i) => {
let posts = this.state.posts;
posts[i].likesCount = !posts[i].isLiked ? posts[i].likesCount + 1 : posts[i].likesCount - 1;
posts[i].isLiked = !posts[i].isLiked;
this.setState({ posts: posts})
}

React native data not rendered after setstate

So i have been working with firebase as a backend in my react native application, i have tried to fetch data this way but i have nothing rendered, i have the activity indicator that went off, but i get that the data array is empty in the application screen, and when i do a console.log, i can see the data in the console, but nothing shows off in the application screen, please help me it's been days that i'm struggling.
export default class Leaderboard extends React.Component{
constructor(props){
super(props)
this.state = {
loading : true,
data : []
}
}
componentDidMount(){
firebase.firestore().collection('rankings').get()
.then(res => {
let rankArray = []
res.forEach(document => {
rankArray.push(document.data())
})
return rankArray;
}).then(res =>{
let data = []
res.forEach(item =>{
firebase.firestore().doc(item.idUser.path)
.get()
.then(doc =>{
let dataItem = {}
dataItem.id = doc.ref.path
dataItem.name = doc.data().fullname
dataItem.points = doc.data().points
dataItem.lc = 'Oran'
data.push(dataItem)
dataItem = {}
})
})
return data;
}).then(res =>this.setState({
loading : false,
data : res
}) ).catch(err => console.log(err))
}
render(){
if(this.state.loading){
return(
<View style = {styles.container}>
<ActivityIndicator size= 'large'></ActivityIndicator>
</View>
)
}else{
console.log(this.state.data)
return(
<View>
<Text>{this.state.data.length}</Text>
<FlatList
data={this.state.data}
renderItem={({item}) => <Text>{item.fullname}</Text>}
/>
</View>
)
}
}
}
The reason for this not working as expected is that you're trying to perform an asynchronous function call, per iteration of your res array inside of your forEach() callback:
// This is asynchronous
firebase.firestore().doc(item.idUser.path).get().then(doc =>{ ... })
Consider revising your code to use the Promise.all() method instead. This will ensure that each asynchronous for individual documents per-item in res array is completed, before setState() in the susequent .then() handler is invoked:
.then(res => {
let rankArray = []
res.forEach(document => {
rankArray.push(document.data())
})
return rankArray;
})
.then(res => {
// Use promise all to resolve each aync request, per item in the
// res array
return Promise.all(res.map(item => {
// Return promise from .get().then(..) for this item of res array.
return firebase.firestore()
.doc(item.idUser.path)
.get()
.then(doc => {
let dataItem = {}
dataItem.id = doc.ref.path
dataItem.name = doc.data().fullname
dataItem.points = doc.data().points
dataItem.lc = 'Oran'
// Return resolve dataItem to array that is relayed to next .then()
// handler (ie where you call this.setState())
return dataItem
})
}));
})
.then(res =>this.setState({
loading : false,
data : res
}))

ReactJS: Check if array contains value else append

I'm trying to check if a JSON response contains a value already inside an array and if it doesn't add it in. The problem I'm having is understanding how to approach this in reactjs. I'm checking before I append it but it doesn't want to work. I've tried passing in user object & user.id but these fail. The attempt below fails to compile but it should help understand what I'm trying to achieve.
Code:
componentWillMount() {
fetch('http://localhost:8090/v1/users')
.then(results => {
return results.json();
})
.then(data => {
data.map((user) => (
if(userList.hasOwnProperty(user.id)) {
userList.push({label: user.title, value: user.id})))
}
})
}
map return the resultant array, but you are not returning anything from it, you should instead use forEach Also you need to check if the userList array contains the id, for that you can use findIndex
What you need is
state = {
userList: [];
}
componentDidMount() {
fetch('http://localhost:8090/v1/users')
.then(results => {
return results.json();
})
.then(data => {
const newUserList = [...this.state.userList];
data.forEach((user) => { // use { here instead of
if(userList.findIndex(item => item.value === user.id) < 0) {
newData.push({label: user.title, value: user.id})
}
})
this.setState({userList: newUserList});
});
}
render() {
return (
{/* map over userList state and render it here */}
)
}
I'd recommend using reduce to turn the returned data into an array you'd like, then adding those values to your existing user list:
fetch('http://localhost:8090/v1/users')
.then(res => res.json())
.then(data => data.reduce((acc, user) => {
const idList = userList.map(user => user.id);
if (idList.indexOf(user.id) === -1) {
acc.push({label: user.title, value: user.id})
}
return acc;
},[]))
.then(newList => userList = [...userList, ...newList]);

Resources