I find myself in a bit of a pickle and can't seem to find an answer on Google.
I'm trying to use the React query library with TSX and display the returning data in a simple list. However it seems that the fetchng and displaying is done only by leaving the tab and coming back to it.
Here's the component
import React, { ChangeEvent, useState, ReactElement } from "react";
import { useQuery, UseQueryResult } from "react-query";
import axios from "axios";
import { API_URL } from "../../settings";
import SearchBar from "../../components/search-bar";
const Employees = (): ReactElement => {
type Employee = Record<string, any>;
const [name, setName] = useState("");
function getValue(eventData: ChangeEvent<HTMLInputElement>) {
console.log(name, "I'm the direct input");
const e = eventData.target.value;
setName(e);
getEmployeesList(name);
}
async function getEmployeesList(name: string) {
const { data } = await axios.get(
API_URL "employees?q[firstname_or_lastname_cont]=" name
);
console.log(data);
return data;
}
const {
data,
error,
isError,
isLoading,
}: UseQueryResult<Employee[], Error> = useQuery("employees", () =>
getEmployeesList(name)
);
if (isLoading) {
return <div>Loading...</div>;
}
if (isError) {
return (
<div>
`Error!
{error?.message}`
</div>
);
}
if (data) {
console.log(data, "I'm the query data");
}
return (
<div className="findEmployees">
<SearchBar
placeholder=""
value={name}
onValueChange={(event: ChangeEvent<HTMLInputElement>) =>
getValue(event)
}
/>
<div className="listContainer">
<h1>Employees</h1>
{data?.map((employee, index: number) => (
<li key={employee.id}>
{employee.firstname} {employee.lastname}
<p>{employee.role}</p>
</li>
))}
</div>
</div>
);
};
export default Employees;
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
Here's the child component
import React, {
ChangeEventHandler,
MouseEvent,
ReactElement,
ReactEventHandler,
} from "react";
import { SearchBarContainer, SearchBarInput } from "./styled-components";
import Icon from "../icon";
interface Props {
placeholder: string;
value: string;
onValueChange: ChangeEventHandler<HTMLInputElement>;
}
const SearchBar = ({
onValueChange,
placeholder,
value,
}: Props): ReactElement => (
<SearchBarContainer>
<SearchBarInput
onChange={onValueChange}
placeholder={placeholder}
value={value}
/>
<Icon color="grey700" name="search" />
</SearchBarContainer>
);
export default SearchBar;
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
So far I haven't found the problem. I tried a custom hook to get and set the data but that obviously didn't change the problem. If anyone has an idea I'll be thankful.
Have a great day
CodePudding user response:
function getValue(eventData: ChangeEvent<HTMLInputElement>) {
const e = eventData.target.value;
setName(e);
console.log(name); // still you should receive previous value
getEmployeesList(e);
}
setState isn't synchronous. It only updates the state value at end of the function call.
CodePudding user response:
thanks for your inputs. I actually solved the problem with a custom hooks
import React, { ChangeEvent, useState, ReactElement } from "react";
import { useQuery, UseQueryResult } from "react-query";
import axios from "axios";
import { API_URL } from "../../settings";
import SearchBar from "../../components/search-bar";
const Employees = (): ReactElement => {
type Employee = Record<string, any>;
const [name, setName] = useState<string>("");
const [eData, setEData] = useState<Employee[]>([]);
function getValue(eventData: ChangeEvent<HTMLInputElement>) {
setName(eventData.target.value);
getEmployeesList(eventData.target.value);
}
async function getEmployeesList(name: string) {
const { data } = await axios.get(
API_URL "employees?q[firstname_or_lastname_cont]=" name
);
setEData(data);
return data;
}
const {
data,
error,
isError,
isLoading,
}: UseQueryResult<Employee[], Error> = useQuery("employees", () =>
getEmployeesList(name)
);
if (isLoading) {
return <div>Loading...</div>;
}
if (isError) {
return (
<div>
`Error!
{error?.message}`
</div>
);
}
return (
<div className="findEmployees">
<SearchBar
placeholder=""
value={name}
onValueChange={(event: ChangeEvent<HTMLInputElement>) =>
getValue(event)
}
/>
<div className="listContainer">
<h1>Employees</h1>
{eData?.map((employee, index: number) => (
<li key={employee.id}>
{employee.firstname} {employee.lastname}
<p>{employee.role}</p>
</li>
))}
</div>
</div>
);
};
export default Employees;
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
As you can see I changed "data" by the hook value "eData". I noticed that my axios query was updated in real time so I took this entry and stocked it in a custom hook which I then mapped on my JSX. Got a real time fetch that way. Furthermore I updated the
function getValue(eventData: ChangeEvent<HTMLInputElement>) {
setName(eventData.target.value);
getEmployeesList(eventData.target.value);
}
part which was requesting with one letter fewer in the first version.