I am not able to implement onClick functionality on AsyncTypeahead to console log the user ID after I find the user. can someone please help. thanks
const SEARCH_URI = 'https://api.github.com/search/users';
const AsyncExample = () => {
const [isLoading, setIsLoading] = useState(false);
const [options, setOptions] = useState([]);
const handleSearch = (query) => {
setIsLoading(true);
fetch(`${SEARCH_URI}?q=${query}+in:login&page=1&per_page=50`)
.then((resp) => resp.json())
.then(({ items }) => {
const options = items.map((i) => ({
avatar_url: i.avatar_url,
id: i.id,
login: i.login,
}));
setOptions(options);
setIsLoading(false);
});
};
const filterBy = () => true;
return (
<AsyncTypeahead
filterBy={filterBy}
id="async-example"
isLoading={isLoading}
labelKey="login"
minLength={2}
onSearch={handleSearch}
options={options}
placeholder="Search for a Github user..."
/>
);
};
Try using onChange, which fires after a menu option has been selected:
<AsyncTypeahead
...
onChange={(selected) => {
console.log(selected[0]?.id);
}}
/>
Note that selected is always an array.
Related
I am getting an infinite loop / crash here.
I'm trying to get an onChange event fired for these radio buttons (which are built after pulling data from a query), but I think it keeps redrawing and I can't figure out why.
Any thoughts on how I can solve this?
const GetChallenge = async () => {
const slug = useParams()
const data = await shopifyApolloClient.query({ query: singleProduct(slug) })
return data
}
const Challenge = () => {
let [loaded, setLoaded] = useState(false)
let [product, setProduct] = useState([])
let [variants, setVariants] = useState([])
let [options, setOption] = useState()
let [metafields, setMetafields] = useState([])
GetChallenge().then((ret) => {
setProduct(ret.data.product)
setVariants(ret.data.product.variants.edges)
setOption(ret.data.product.variants.edges[0].node.title)
setMetafields(ret.data.product.metafields.edges)
setLoaded(true)
})
const handleOptions = (event) => {
setOption(event.target.value)
}
if (loaded === true) {
return (
<div>
{variants.map((e) => (
<label
htmlFor={e.node.title}
key={e.node.id}>
<input
type="radio"
name="options"
checked={e.node.title === options}
value={e.node.title}
onChange={handleOptions}
/>
{e.node.title}
</label>
))}
</div>
)
} else {
return (
<p>Not Loaded</p>
)
}
}
GetChallenge is triggering every render. Try useEffect with the empty array empty soas to trigger only onmount.
import React, { useState, useEffect } from 'react';
const GetChallenge = async () => {
...
useEffect(() => {
GetChallenge().then((ret) => {
setProduct(ret.data.product)
setVariants(ret.data.product.variants.edges)
setOption(ret.data.product.variants.edges[0].node.title)
setMetafields(ret.data.product.metafields.edges)
setLoaded(true)
}),[]}
...
}
Try this:
onChange={(event) => setOption(event.target.value)}
hope this will solve your problem :)
import React, { useState, useEffect } from 'react';
const GetChallenge = async () => {
const slug = useParams();
const data = await shopifyApolloClient.query({ query: singleProduct(slug) });
return data;
};
const Challenge = () => {
const [data, setData] = useState({
loaded: false,
product: [],
variants: [],
options: "",
metafields: []
});
const { loaded, variants, options } = data;
useEffect(() => {
GetChallenge().then((ret) => {
setData((prevState) => ({
...prevState,
product: ret.data.product,
variants: ret.data.product.variants.edges,
options: ret.data.product.variants.edges[0].node.title,
metafields: ret.data.product.metafields.edges,
loaded: true
}));
});
}, []);
const handleOptions = (event) => {
setData((prevState) => ({ ...prevState, options: event.target.value }));
};
if (loaded === true) {
return (
<div>
{variants.map((e) => (
<label htmlFor={e.node.title} key={e.node.id}>
<input
type="radio"
name="options"
checked={e.node.title === options}
value={e.node.title}
onChange={(event) => handleOptions(event)}
/>
{e.node.title}
</label>
))}
</div>
);
} else {
return <p>Not Loaded</p>;
}
};
I am trying to update the database. So I have an input field that is disabled as default. So when you click, editing is enabled and when you click outside of the input field, it gets disabled again. What I am trying to do is update when you click outside of the input field. So, my input is like this:
const InputPrice = ({ mainPricePosts, handleChange }) => {
const [disabled, setDisabled] = useState(true);
const [priceValue, setPriceValue] = useState(mainPricePosts);
function handleClick() {
if (disabled === true) {
setDisabled(false);
}
}
return (
<>
<Form.Control
type="text"
className="price_coefficient_input"
value={priceValue}
onBlur={() => {
setDisabled(true);
handleChange(priceValue);
}}
onChange={handleChange(mainPricePosts)}
readOnly={disabled}
onClick={handleClick}
/>
</>
);
};
InputPrice.propTypes = {
mainPricePosts: PropTypes.object.isRequired,
handleChange: PropTypes.func.isRequired,
};
export default InputPrice;
And this is how I am trying to update but I am not sure if I am doing right to get the value from the input field:
const [updatePosts, setUpdatePosts] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [show, setShow] = useState(false);
const [showError, setShowError] = useState(false);
const handleClose = () => setShow(false);
const handleCloseError = () => setShowError(false);
const fetchIndividualPosts = async ({ value, post: { mainPricePosts, key } = {} }) => {
console.log(value);
try {
setLoading(true);
const res = await Axios({
method: "POST",
url: `url`,
headers: {
"content-Type": "application/json",
},
data: {
updated_parameter: ["main_price", "small_car", key],
updated_value: value,
},
});
if (res.status === 200) {
setUpdatePosts(res.data);
}
setLoading(false);
} catch (err) {
console.log(err.response.status);
setError(err.response.data.error);
setLoading(false);
}
};
const handleChange = (mainPricePosts) => (e) => {
fetchIndividualPosts({ mainPricePosts, value: e.target.value });
};
This is also the curl how I can update the data:
curl -L -i -H "Content-Type: application/json" -X POST -d '{
"updated_parameter":["100"],
"updated_value":"0.044"
}' $ip''
so updated_value should be the updated input (the value after, outside is clicked)
100, should be the key of the input value.
Hope it is clear and you can help me about this problem.
Thanks for your help beforehand.
There are many ways you can achieve what you need, but I would use following approach.
In your InputPrice component on onBlur event I would disable input by calling setDisabled(true) and then use useEffect hook to call handleChange callback if new price value and original price values are different. Because you are calling setDisabled(true), you're actually re-rendering your InputPrice component and therefore not executing handleChange callback.
Checkout code below.
const InputPrice = ({ mainPricePosts, handleChange }) => {
const [disabled, setDisabled] = useState(true);
const [priceValue, setPriceValue] = useState(mainPricePosts);
function handleClick() {
if (disabled === true) {
setDisabled(false);
}
}
useEffect(() => {
let callUpdateCallback = false;
if (priceValue !== mainPricePosts) callUpdateCallback = true;
if (disabled && callUpdateCallback) handleChange(priceValue);
}, [disabled, priceValue, handleChange, mainPricePosts]);
return (
<>
<Form.Control
type="text"
className="price_coefficient_input"
value={priceValue}
onBlur={setDisabled(true)}
onChange={(e) => setPriceValue(e.target.value)}
readOnly={disabled}
onClick={handleClick}
/>
</>
);
};
InputPrice.propTypes = {
mainPricePosts: PropTypes.object.isRequired,
handleChange: PropTypes.func.isRequired,
};
export default InputPrice;
You call this component like this
import React from "react";
import ReactDOM from "react-dom";
import InputPrice from "./InputPrice";
function App() {
const handleChange = (e) => {
console.log("app handle change", e);
// You can call your fetch here...
};
return (
<div>
<InputPrice mainPricePosts="500" handleChange={handleChange} />
</div>
);
}
ReactDOM.render(<App />, document.querySelector("#root"));
Additionally there codesandbox that used to debug it, so if you need more details you can find it on the link below.
https://codesandbox.io/s/reactjs-playground-forked-8vwe2?file=/src/index.js:0-364
I'm fetching data from a firebase db it works when the component renders, but I can't make it to fetch again when there is a new entry in my db.
What I've tried
I've tried passing a state to the dependency array of useEffect and I changed that state every time my form was submitted (That's the time when there's a new entry in my db)
App
function App() {
const [showForm, setShowForm] = useState(true);
const [tasks, setTasks] = useState([]);
const [isSubmitted, setIsSubmitted] = useState(true);
//Fetch tasks from server
const fetchData = () => {
fetch(
"https://react-task-tracker-8e519-default-rtdb.firebaseio.com/tasks.json"
)
.then((response) => {
return response.json();
})
.then((data) => {
const tasks = [];
//Convert the data to an array so i can map over it
for (const key in data) {
const task = {
id: key,
...data[key],
};
tasks.push(task);
}
setTasks(tasks);
});
};
useEffect(() => {
fetchData();
}, [isSubmitted]);
//Show/Hide form
const onAddHandler = () => {
setShowForm(!showForm);
};
const formSubmitted = () => {
setIsSubmitted(!isSubmitted);
console.log(isSubmitted);
};
return (
<Container>
<Header click={onAddHandler} isShown={showForm}></Header>
{showForm ? <Form fs={formSubmitted}></Form> : ""}
<Tasks tasks={tasks}></Tasks>
</Container>
);
}
export default App;
Form
function Form(props) {
const [task, setTask] = useState();
const [dayTime, setDayTime] = useState();
const [reminder, setReminder] = useState();
//Posting Form data to firebase (DUMMY API)
const postFormData = (fullTask) => {
fetch(
"https://react-task-tracker-8e519-default-rtdb.firebaseio.com/tasks.json",
{
method: "POST",
body: JSON.stringify(fullTask),
headers: {
"Content-Type": "application/json",
},
}
);
};
//Make an object of form data
const onSubmit = (e) => {
e.preventDefault();
const fullTask = {
task: task,
dayTime: dayTime,
reminder: reminder,
};
//Post func call
postFormData(fullTask);
props.fs();
//Field clearing
setTask("");
setDayTime("");
setReminder("");
};
return (
<AddForm onSubmit={onSubmit}>
<FormControl>
<Label>Task</Label>
<Input
type="text"
placeholder="Add Task"
onChange={(e) => setTask(e.target.value)}
value={task}
required
></Input>
</FormControl>
<FormControl>
<Label>Day & Time</Label>
<Input
type="text"
placeholder="Add Task"
onChange={(e) => setDayTime(e.target.value)}
value={dayTime}
required
></Input>
</FormControl>
<FromControlCheck>
<CheckLabel>Set Reminder</CheckLabel>
<CheckInput
type="checkbox"
onChange={(e) => setReminder(e.currentTarget.checked)}
value={reminder}
></CheckInput>
</FromControlCheck>
<Submit type="submit" value="Save Task"></Submit>
</AddForm>
);
}
export default Form;
I would pass fetchData as a props to <Form>. When submitted, I would call it.
Form
const onSubmit = async (e) => {
e.preventDefault();
const fullTask = {
task: task,
dayTime: dayTime,
reminder: reminder,
};
//Post func call
await postFormData(fullTask);
await props.fetchData();
//Field clearing
setTask("");
setDayTime("");
setReminder("");
};
Then remove the isSubmitted state.
Try change the "Id" value to "id". Try make it the same name as the key for the id in "fecthData" function.
I think this solve your problem
function App() {
const [showForm, setShowForm] = useState(true);
const [tasks, setTasks] = useState([]);
const [isSubmitted, setIsSubmitted] = useState(false);
//Fetch tasks from server
const fetchData = () => {
fetch(
"https://react-task-tracker-8e519-default-rtdb.firebaseio.com/tasks.json"
)
.then((response) => {
return response.json();
})
.then((data) => {
const tasks = [];
//Convert the data to an array so i can map over it
for (const key in data) {
const task = {
id: key,
...data[key],
};
tasks.push(task);
}
setTasks(tasks);
});
};
useEffect(() => {
if (isSubmitted) {
fetchData();
setIsSubmitted(false);
}
}, [isSubmitted]);
//Show/Hide form
const onAddHandler = () => {
setShowForm(!showForm);
};
const formSubmitted = () => {
setIsSubmitted(true);
console.log(isSubmitted);
};
return (
<Container>
<Header click={onAddHandler} isShown={showForm}></Header>
{showForm ? <Form fs={formSubmitted}></Form> : ""}
<Tasks tasks={tasks}></Tasks>
</Container>
);
}
export default App;
My Functional component is as follows:
const Scratch = () => {
const [isLoaded, setIsLoaded] = useState(false);
const colorSelectItems=[];
const [selectedColor, setSelectedColor] = useState("fffff");
useEffect(() => {
fetch(
`http://localhost:8765/fetchData?userId=1`
)
.then((response) => response.json())
.then((data) => {
createDropDown(data));
setIsLoaded(true);
});
}, []);
const createDropDown= (data) => {
data.map((color) => {
colorSelectItems.push({
label: color.colorName,
value: color.hexValue,
});
});
return (
<div className="commonMargin">
{!isLoaded&& <p>Loading..</p>}
{isLoaded&& (
<Dropdown
value={selectedColor}
optionLabel="label"
options={colorSelectItems}
onChange={(e) => setSelectedColor(e.target.value);}
/>
)}
</div>
);
};
export default Scratch;
The problem is, it is displaying Loading... until the API call is complete, and it is rendering DropDown after that. But even after the completion of API call, the DropDown is still empty!
What am I missing here?
PS: This DropDown works perfectly if I replace fetching data from API to fetching data from local json file
Try this .In case any problem plz reply
const Scratch = () => {
const [isLoaded, setIsLoaded] = useState(false);
const colorSelectItems=[];
const [selectedColor, setSelectedColor] = useState("fffff");
useEffect(() => {
fetch(
`http://localhost:8765/fetchData?userId=1`
)
.then((response) => response.json())
.then((data) => {
var temp=data?.map((item)=>({label: item?.colorName,
value: item?.hexValue }));
colorSelectItems=temp;
setIsLoaded(true);
});
}, []);
return (
<div className="commonMargin">
{!isLoaded&& <p>Loading..</p>}
{isLoaded&& (
<Dropdown
value={selectedColor}
optionLabel="label"
options={colorSelectItems}
onChange={(e) => setSelectedColor(e.target.value);}
/>
)}
</div>
);
};
export default Scratch;
I have a map that render few items and i need when one element from map slected modal should load data about this selected items' id inside modal.
Like that:
<ListGroup>
{userinfo.map(item =>
(
<>
<ListGroup.Item key={item.id} onClick={handlePassInfoShow}>
{item.name}</ListGroup.Item>
</>
)
)}
</ListGroup>
<ModalPassInfo
modelClose={() => handlePassInfoClose()}
modelShow={showPaaInfo}
//id={item.id}
setshowPaaInfo={setshowPaaInfo}
/>
Here I am mapping through the user's array and adding a listgroup item to each of them with onClick modal. Now, whenever something is clicked inside map, the modal should be opened and read data about selected item.
And my modal like that.
const ModalPassInfo = ({modelShow, modelClose, id, showPaaInfo}) => {
const ref = React.createRef();
const [isError, setError] = useState(false);
const [isLoading, setLoading] = useState(true);
const [country_list, setCountries] = useState([]);
const [message, setMessage] = useState("");
const [data, setData] = useState({
//data about user
});
useEffect(() => {
loadNetwork();
}, []);
const loadNetwork = () => {
setLoading(true);
setError(false);
const selector = api.getItems("selector", {
tables: "country_list"
}).then(res => {
let response = res.data;
setCountries(response.country_list);
});
const data = api.getItems(`user-info/${id}`, {
}).then(res => {
let response = res.data;
setData(response);
});
Promise.all([selector, data]).then(res => {
console.log(res);
setError(false);
setLoading(false);
}).catch(e => {
console.log(e);
setMessage(e.toString());
setLoading(false);
setError(true);
});
};
const onRefresh = () => {
loadNetwork();
};
if (isError) {
return <ErrorMessage message={message} onRefresh={onRefresh}/>
}
if (isLoading) {
return <Loader/>
}
If I go to the page, the modal is loading immediately. And during onClick, only the last item id is retrieved.
And moy consts
const [showPaaInfo, setshowPaaInfo] = useState(false);
const handlePassInfoClose = () => setshowPaaInfo(false);
const handlePassInfoShow = () => {
setshowPaaInfo(true)
};
My question is. Any item on the map should send an id to the modal when the item is clicked. Where am I wrong?
Define one state
const [show, setShow] = React.useState(false);
function
const handlePassInfoShow = (data){
setShow(true);
console.log(data);
}
Change this to
<ListGroup>
{userinfo.map(item =>
(
<>
<ListGroup.Item key={item.id} onClick={()=>handlePassInfoShow(item)}>
{item.name}</ListGroup.Item>
</>
)
)}
</ListGroup>
{show && ( <ModalPassInfo
modelClose={() => handlePassInfoClose()}
modelShow={showPaaInfo}
//id={item.id}
setshowPaaInfo={setshowPaaInfo}
/>
)}