I have saved a query in a DB and recalled it for running again. However, I do not know how re-run the query.
I obtain the query in the onChange and saved the value to the DB as a string for recalling later so it can be worked on.
<ReactiveBase app={this.props.app} url={config.elastic.URL} >
<StateProvider
onChange={(prevState, nextState) => {
queryString = nextState;
console.log('onChange');
}}
I was looking at a way to put that query string in the DataSearch component if that is the correct thing to do. The query is quite large as I have additional components attached to the search.
If I set the value of the DataSearch to my queryString I can not type in the search bar
<DataSearch
dataField={this.props.refinement.searchBar}
componentId="search"
placeholder="Search books or videos"
autosuggest={false}
debounce={debounce}
showClear={true}
customQuery={this.props.customQuery}
defaultValue={this.props.defaultValue}
value={queryString}
>
</DataSearch>
also the query is an elastic search query so I get a search bar full of JSON. I can get the indavidual elements and set queryString to that which gives me half of what I want but with a searchbar I can not type into.
var objectQuery = JSON.parse(selectedQueryString);
queryString = objectQuery.search.value;
Update
This helped in being able to type in the searchBar and update the value and may even be most of the way there for the DataSearch component.
value={this.state.value}
onChange={(value, triggerQuery, event) => {
this.setState(
{
value,
},
() => triggerQuery(),
);
}}
You can not push the query string back into the component and let it handle all the components used to create the query. You have to get the values from the query string and set the values of the components again. The query then will be re-run using via the onChange mehtod.
Related
I have a few useQuery() calls in my react component like this:
const {...} = useQuery(["person.getAll", ....
const {...} = useQuery(["person.getCounts", ....
Then later in a click event after some DELETE/POST request is finished I try to invalidate above queries:
queryClient.invalidateQueries("person");
But it does not trigger the re-fetch.
I thought it's some state management issues from my part but then I tried invalidating a specific query like
queryClient.invalidateQueries("person.getAll");
and it works fine..
Is partial query key matching not working in react-query ?
React-Query invalidation works off based array prefixes, not string prefixes.
Your useQuery calls should look like this:
const {...} = useQuery(["person", "getAll", ....
const {...} = useQuery(["person", "getCounts", ....
And then you invalidateQueries call will work, with a slight change:
queryClient.invalidateQueries({
queryKey: ["person"]
}); // invalidate all query keys which start with "person"
queryClient.invalidateQueries(["person"]); // this also works
Alternative, if you are locked into your current syntax, you can accomplish the same using a predicate:
queryClient.invalidateQueries({
predicate: query =>
query.queryKey[0].startsWith("person"),
})
But this breaks the React-Query convention.
If you see the last example in the invalidateQueries docs, it provides an option for maximum granularity
If you find yourself wanting even more granularity, you can pass a predicate function to the invalidateQueries method. This function will receive each Query instance from the query cache and allow you to return true or false for whether you want to invalidate that query:
So, for your scenario the following should work
queryClient.invalidateQueries({
predicate: query =>
query.queryKey[0].startsWith('person'),
})
This is a matter of how you are structuring the queryKey array. The first constant value of your queryKey array is a whole string, based on what you provided the partial matching won't work if you try to invalidate the queries based on just a part of that string. For this to work, you'd need to structure the queryKey array like so:
const {...} = useQuery(["person", "getAll", ....
const {...} = useQuery(["person", "getCounts", ....
Now the invalidation should work as expected because it's matching all queries that start with "person" in their query key:
queryClient.invalidateQueries(["person"]);
Reference of this on the docs
I'm currently working on a springboot/reactjs project. I'm using the react select library to set a multi select input in one of my forms but I could not get the selected values here's some code to make it a bit clearer.
these are my options generated dynamically from the database each option has the webService Id as a value
this is my select input, I need to get the selected values "Ids" and then call the method that retrieves the webservices from the database and then assign the list of webServices to my newApplicationData.webservices
this is the get web service function
Update : I kind off found a solution to my problem : on the onChange prop I used this
onChange={(selectedOptions) => {
const state = this.state;
state.selectedWebServices = [];
selectedOptions.forEach((option) => {
this.getWS(option.value);
state.selectedWebServices.push(this.state.getWSData);
});
state.newApplicationData.webServices =
state.selectedWebServices;
this.setState(state);
}}
and then I found out another problem: even if I select two deffrent options the list of selected options only gets one duplicated option????!!!!
I'm having a hard time figuring out how to update a list of items (in the cache). When a new item is created with react-apollo.
The <CreateItemButton /> component is (in my case) not nested within <ListItems /> component. From what I can figure out, I need to update the cache via the update function in my createItemButton <Mutation /> component.
The problem is when I try to store.readQuery({query: GET_LIST_ITEMS, variables: ???}) to get the current list of items (to append my recently created item), this can have variables/filters (for pagination, sorting etc.).
How do I know what variable to pass to the store.readQuery function, is there a sort of "last used variables" around this, or do you have any other suggestion on how to solve this issue?
This is a known Apollo issue and the team is working on it. The current options you have can be found in this medium post.
It is also an issue with deleting/updating an item when you have it in a list with filters or pagination.
Here is a reference of an opened issue on Github about it
This seems to work, but a bit hacky to access the cache.watches Set? :S
The trick is to access the cache's variables for a given query, save it and perform a refetch with the given query variables. In my case after creation of an item:
export const getGraphqlCacheVariables = (queryName, cache) => {
if (cache.watches) {
const watch = [...cache.watches].find(w => !!w.query[queryName]);
if (watch) {
return watch.variables;
}
}
};
The mutation update function:
let variables;
const update = (cache, { data }) => {
if (data && data.createTask && data.createTask.task) {
variables = getGraphqlCacheVariables('GetTasks', cache);
}
}
And the refetchQueries function:
const refetchQueries = () => {
if (variables && Object.keys(variables).length > 0) {
return [{ query: GET_TASKS, variables }];
}
return [];
}
Bot the update and refetchQueries functions should have access to the variables variable
The benefit compared to the solution in the Medium article, is that you're not deleting the cached data for a given query (GET_TASKS) with different variables.
Apollo now provides a new directive that allows ignoring of some variables when querying the cache. Check it here. I've used it to ignore my changing pagination params.
I've got an app using mobx-state-tree that currently has a few simple stores:
Article represents an article, either sourced through a 3rd party API or written in-house
ArticleStore holds references to articles: { articles: {}, isLoading: bool }
Simple scenario
This setup works well for simple use-cases, such as fetching articles based on ID. E.g.
User navigates to /article/{articleUri}
articleStoreInstance.fetch([articleUri]) returns the article in question
The ID is picked up in render function, and is rendered using articleStoreInstance.articles.get(articleUri)
Complex scenario
For a more complex scenario, if I wanted to fetch a set of articles based on a complex query, e.g. { offset: 100, limit: 100, freeTextQuery: 'Trump' }, should I then:
Have a global SearchResult store that simply links to the articles that the user has searched for
Instantiate a one-time SearchResult store that I pass around for as long as I need it?
Keep queries and general UI state out of stores altogether?
I should add that I'd like to keep articles in the stores between page-loads to avoid re-fetching the same content over and over.
Is there a somewhat standardized way of addressing this problem? Any examples to look at?
What you need might be a Search store which keeps track of following information:
Query params (offset, limit, etc.)
Query results (results of the last search)
(Optional) Query state (isLoading)
Then to avoid storing articles in 2 places, the query results should not use Article model, but reference to Article model. Anytime you query, the actual result will be saved in existing store ArticleStore, and Search only holds references:
import { types, getParent, flow } from 'mobx-state-tree'
const Search = types.model({
params: // your own params info
results: types.array(types.reference(Article))
}).views(self => ({
get parent() {
return getParent(self) // get root node to visit ArticleStore
}
})).actions(self => ({
search: flow(function*(params) {
this.params = params // save query params
const result = yield searchByQuery(query) // your query here
this.parent.articleStore.saveArticles(result) // save result to ArticleStore
this.results = getArticleIds(result) // extract ids here for references
})
}))
Hope it's what you are looking for.
I will reduce the issue to a simple example. I have a table component rendering a table with queried data. I also have a small form that allows users to input data into the table. The issue i am having is that the default value of the input fields are empty strings.
Sample input field:
<td><input type="text" placeholder="Nombre" name="name" onChange={this.handleChange} value={this.state.name}/></td>
Assume that the state is holding an empty string as default value for the input field
this.state={name:' '}
Assume also that i want to send in my form an empty string to the database. I am doing the mutation the apollo way, with graphql:
const ADD_CONTACTS = gql`
mutation createContact(
$name: String,
){
createContact(
name: $name
){
id
name
}
}`
<Mutation mutation={ADD_CONTACTS}>
{createContact=>(
<form onSubmit={async e=> {
e.preventDefault();
let name = this.state.name;
await createContact({variables : {
"name":name
} })
}}
>
<table>
... table markup with input fields
</form>
)}
</Mutation>
Ok, that's the general context. In actuality the form contains 6 fields. But the issue is that when I send an empty string to the query inside the variable, the moment it sends the query to the server it changes the empty string to a null value so that i end up with this error:
GraphQL error: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null
I have tested the server using graphiql and the requests themselves can accept empty strings, but it seems to be that the mutation component or apollo, somewhere, is converting my empty string that im passing to the graphql variables into null.
I have managed to make a workaround for this scenario, but it's definitely not the right way to deal with this. If I could somehow get apollo to actually send empty strings instead of null it would solve the issue.
thanks to anyone that has any idea why this i
Try removing async and await.