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

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.

Related

React component uses old data from previous API call

I am using React Query to fetch data from an API I have built. The component is rendering the old data from the previous api call and not updating with new the data from the new api call.
The new data is only rendering when I refresh the page.
Component:
export const ProfilePageStats = (props: {
user: User;
id: number;
}) => {
const { chatId } = useParams();
const { status: subscribeStatus, data: subscribeData } =
useSubscriptionsWithType(
chatId ? chatId : "",
props.id,
props.user.id,
"SUBSCRIBE"
);
const { status: unsubscribeStatus, data: unsubscribeData } =
useSubscriptionsWithType(
chatId ? chatId : "",
props.id,
props.user.id,
"UNSUBSCRIBE"
);
if (unsubscribeStatus == "success" && subscribeStatus == "success") {
console.log("Working", unsubscribeData);
return (
<ProfilePageStatsWithData
user={props.user}
subscribed={Object.keys(subscribeData).length}
unsubscribed={Object.keys(unsubscribeData).length}
/>
);
}
if (unsubscribeStatus == "error" && subscribeStatus == "error") {
console.log("error");
return <ProfilePageStatsLoading />;
}
if (unsubscribeStatus == "loading" && subscribeStatus == "loading") {
console.log("loading");
return <ProfilePageStatsLoading />;
}
return <ProfilePageStatsLoading />;
};
export const useSubscriptionsWithType = (
chatId: string,
id: number,
userId: number,
type: string
) => {
return useQuery(
["subscriptionsWithType"],
async () => {
const { data } = await api.get(
`${chatId}/subscriptions/${id}/${userId}?type=${type}`
);
return data;
},
{
enabled: chatId > 0 && userId > 0,
refetchOnWindowFocus: false,
}
);
};
The component should update to show the new user values but shows the previous user values. If I click out and select a different user entirely it then shows the values for the previously clicked user.
I can see that React Query is fetching with the correct values for the query but the component still renders the old user data?
It turns out that the fetchStatus value is changing to "fetching" but it not actually calling the api. Hence, why its only using the old values?
Your key part of the useQuery is what tells the hook when to update.
You only use ["subscriptionsWithType"] as key, so it will never know that you need to refetch something.
If you add userId there, it will update when that changes.
So, using
return useQuery(
["subscriptionsWithType", userId],
async () => {
...
will work.
It is likely, that you want all the params, that you use in the url, to be added there.
I solved it by adding a useEffect and refetching based on the changing user id.
useEffect(() => {
refetch();
}, [props.user.id]);

react-select when change view missing selected value

How can I keep selected options by react-select async? What I mean I have the following component which is inside of a form with multiple steps when I step back to the part where I use AsyncSelect I see placeholder and load options fire again(get all value from API) selected values. how to keep the selected value. this is my AsyncDropDown.js :
<AsyncSelect
styles={customStyles}
cacheOptions
loadOptions={loadOptions}
defaultOptions
onChange={handleChange}
isRtl={true}
isSearchable={false}
classNamePrefix='myDropDown'
placeholder={'(پیش فرض گروه فعال)'}
/>
and this loadOtions function :
const loadOptions = (selectedOption, callback) => {
let token = localStorage.getItem('Token')
let udid = localStorage.getItem('UUID')
let xml = `body of request`;
axios.post('myurl.com', xml, { headers: { 'Content-Type': 'text/xml;charset=UTF-8' } }).then(function (response) {
//console.log(response)
var options = {
attributeNamePrefix: "#_",
attrNodeName: "attr", //default is 'false'
textNodeName: "#text",
ignoreAttributes: true,
ignoreNameSpace: false,
allowBooleanAttributes: false,
parseNodeValue: true,
parseAttributeValue: false,
trimValues: true,
cdataTagName: "__cdata", //default is 'false'
cdataPositionChar: "\\c",
localeRange: "", //To support non english character in tag/attribute values.
parseTrueNumberOnly: false,
attrValueProcessor: a => he.decode(a, { isAttributeValue: true }),//default is a=>a
tagValueProcessor: a => he.decode(a) //default is a=>a
};
// Intermediate obj
var tObj = parser.getTraversalObj(response.data, options);
var jsonObj = parser.convertToJson(tObj, options);
if (jsonObj["soap:Envelope"]["soap:Body"].GetAllCategoriesResponse.GetAllCategoriesResult["diffgr:diffgram"].DocumentElement != null) {
var jsonDropDownDetails = jsonObj["soap:Envelope"]["soap:Body"].GetAllCategoriesResponse.GetAllCategoriesResult["diffgr:diffgram"].DocumentElement.CATEGORY
jsonDropDownDetails.map(item => {
const data = { value: item.CATEGORYNAME, label: item.CATEGORYNAME, index: item.CATEGORYID }
setDropDownOptions(dropDownOptions.push(data))
})
callback(dropDownOptions)
}
setIsLoading(false)
}).catch(function (error) {
console.log("erorr in DropDown : " + error)
})
};
and this is handelChange function :
const handleChange = selectedOption => {
setSelectedOption(selectedOption)
props.parentCallBack(selectedOption)
};
this is the Async Dropdown component use this component to the main view when in the main view go to the next view and get back to the main view missing selected Value and show placeHolder and call loadOptions function again and call API. how to solve this issue?
In order to retain values of your form fields when you click/next or previous:
Create a main form component say MasterForm and and render the form-steps say Step1 and Step2(which holds your input fields etc).
Maintain the value of your select in MasterForm and the values and onChangeHandlers the form steps.
I have created a working demo of react-select multi step form
MasterForm:
...
render() {
return (
<>
<Step1
value={this.state.step1SelectValue}
handleChange={e => {
this.setState({ step1SelectValue: e });
}}
currentStep={this.state.currentStep}
/>
<Step2
value={this.state.step2SelectValue}
handleChange={e => {
this.setState({ step2SelectValue: e });
}}
currentStep={this.state.currentStep}
/>
{this.previousButton()}
{this.nextButton()}
</>
);
}
...
Step1.js
...
<AsyncSelect
cacheOptions
loadOptions={this.loadOptions}
defaultOptions
onChange={this.props.handleChange}
isRtl={true}
isSearchable={false}
classNamePrefix="myDropDown"
placeholder={"(پیش فرض گروه فعال)"}
value={this.props.value}
...
Note:
You seem to not use search feature in your select. So I guess you can simply use normal Select and handle data fetching on your own in componentDidMount. See Step2 in my code demo
If you don't want to execute your loadOptions function for all the re-renders consider to use useMemo . Note that useMemo is available in functional components

How to properly fetch data from async storage in react native?

I am attempting to load and retrieve local data through asynchronous storage. I've laid out the current set up on a page, but am unable to retrieve data. Data is definitely saved as I receive a notification about it once I click store data. But when I proceed to call data it returns a null value. What am I doing something wrong here?
const STORAGE_KEY = '#save_enableauto'
state={
enableAuto:false
}
_storeData = async enableAuto => {
try {
let x = toString(enableAuto);
await AsyncStorage.setItem(STORAGE_KEY, x)
alert('Data successfully saved!')
//this.setState({ enableAuto: x })
} catch (e) {
console.log(e)
alert('Failed to save name.')
}
}
_retrieveData = async () => {
console.log('trying to call data')
try {
const enableAuto = await AsyncStorage.getItem('STORAGE_KEY');
console.log(enableAuto)
if (enableAuto !== null) {
// We have data!!
console.log(enableAuto);
}
} catch (error) {
alert('failed to load previous settings.')
// Error retrieving data
}
};
...
<Button title={'Store Data'} onPress={() => this._storeData(this.state.enableAuto)}/>
<Button title={'call Data'} onPress={() => this._retrieveData()}/>
</View>
<View>
<CheckBox
value={this.state.enableAuto}
onValueChange={() => this.setState({ checked: !this.state.enableAuto })}
/>
The error above is while you are storing, you are setting :
await AsyncStorage.setItem(STORAGE_KEY, x)
and here STORAGE_KEY refers to value #save_enableauto
But while you are retrieving data
const enableAuto = await AsyncStorage.getItem('STORAGE_KEY');
you are giving 'STORAGE_KEY' as string , so that means its refering 'STORAGE_KEY' and it doesnt have any stored value. Try this
const enableAuto = await AsyncStorage.getItem(STORAGE_KEY);
Hope it helps. feel free for doubts

React fetching parameters from URL

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>
)
}

Optional field inside Options React Select

Hey guys im trying to create a autosuggestion in cooperation with redux-form. Im using the Creatable approach. I loading my options via an external API. The problem is, i need a extra field in every Option Object. {value: "test#gmx.de", label: "test#gmx.de", dn:"CN...." }. Is there a possibility to do so?
I typically add my own properties inside the callback for the API request, just before setting the options in the state. For example...
axios.get('/some/api/request')
.then(response => {
const options = response.data.map(item => {
// Add whatever custom properties you want here
return ({value: "test#gmx.de", label: "test#gmx.de", dn:"CN...." })
})
// set your options in the state to the new options constant from above
dispatch(change('formName', 'options', options))
Hope this helps!
//Handle change with either selectedOption
handleChange(selectedOption){
this.setState({ selectedOption })
if(this.props.onOptionSelect){
this.props.onOptionSelect(selectedOption.data)
}
}
loadOptions(input, callback) {
this.props.loadOptions(input).then(options => {
callback(null, {options: options})
})
}
render() {
const {selectedOption} = this.state
const selectClass = this.props.meta.touched && this.props.meta.error ? "has-error form-group" : "form-group"
return (
<div className={selectClass}>
<AsyncCreatable
value={selectedOption}
onChange={this.handleChange}
loadOptions={this.loadOptions}
isLoading={false}
placeholder={this.props.label}
promptTextCreator={(label) => this.props.promtLabel(label)}
onBlur={() => this.props.input.onBlur(selectedOption.value || "")}
/>
</div>
)
}
//Function to convert incomming users in usable options (React Select)
export const convertADUsersToOptions = users => {
return users.map(user => {
return {
value: normalizeDN(user.dn),
label: user.mail
}
})
}

Resources