I have an app that pulls data from a GraphQL database and then .maps it into custom form components (quantity number textboxes). Right now, the components themselves are holding state of their individual quantities, but I need to be able to access the values from the Parent so I can change the amounts using inputs elsewhere in the app. I've looked around at how this is done and I think this might be what I need, but I don't know how to apply it: [How to target DOM with React useRef in map][1]
My app is made up of a parent element with a Top Bar containing an input, a Modal component, and a map of elements populated from the GraphQL query.
export default function Home() {
const [batch, setBatch] = useState([]);
const [target, setTarget] = useState("");
const [batchCount, setBatchCount] = useState(0);
const [cartModalStatus, setCartModalStatus] = useState(false);
const elementValues = useRef([]);
const fetcher = query => request("https://data.objkt.com/v2/graphql", query);
const { data, error } = useSWR(
`{
listing(where: {token: {creators: {creator_address: {_eq: ` + target + `}}, supply: {_gt: "0"}}, status: {_eq: "active"}}, order_by: {token: {timestamp: asc}, price: asc}) {
token {
name
display_uri
timestamp
supply
}
price
seller {
address
alias
}
amount_left
}
}`, fetcher);
const handleItemCount = () => {
let count = 0;
for (let i = 0; i < batch.length; i++)
count += batch[i][1];
setBatchCount(count);
}
const onCartClick = () => {
setCartModalStatus(true);
}
const onHideModal = () => {
setCartModalStatus(false);
}
const onSubmit = (e) => {
console.log(e);
setTarget(e.target[0].value);
e.preventDefault();
};
const onChange = (el, quantity) => {
let batchCopy = batch;
let found = false;
let foundIndex;
for (var i = 0; i < batchCopy.length; i++)
if (batchCopy[i][0] === el)
{
found = true;
foundIndex = i;
}
if (!found) batchCopy.push([el, quantity]);
else if (found) batchCopy[foundIndex][1] = quantity
setBatch(batchCopy);
handleItemCount();
};
return (
<Container>
<TopBar onSubmit={onSubmit} cartTotal={batchCount} onCartClick={onCartClick}/>
<CartModal show={cartModalStatus} onHideModal={onHideModal} batch={batch}/>
<DataMap target={target} onChange={onChange} data={data} error={error}/>
</Container>
)
}
The DataMap is the data from the query. I need to match each element to a quantity, which I've done by keeping individual state in each child element, but I need the parent to have access to the quantity.
export function DataMap(props){
const onChange = (el, quantity) => {
console.dir(el);
props.onChange(el, quantity);
};
if (props.target === "") return <div>No target.</div>;
if (props.target !== "" && validateAddress(props.target) !== 3) return <div>Invalid address.</div>;
if (props.error) {
console.log(props.error);
return <div>Failed to Load</div>;
}
if (!props.data) return <div>Loading...</div>;
if (!props.error && props.data){
return <Row>
{props.data["listing"]
.map((el, i , arr) => {
return (
<Col key={i} id={i} xs={4} sm={4} md={3} lg={2}>
<StateImg src={"https://ipfs.io/ipfs/" + el["token"]["display_uri"].slice(7,)}/>
<h5>{el["token"]["name"]}</h5>
<p>{el["price"] / 1000000} {" xtz"}</p>
<Row>
<QuantityForm remaining={el["amount_left"]} onChange={onChange} element={el}/>
</Row>
</Col>)
})}
</Row>
}
}
Lastly, QuantityForms are just the form input for the quantity of each item. Right now state is kept in each individual element and passed up to the parent's "batch" state, but that means I can't alter the quantities other than using these specific inputs.
export function QuantityForm(props){
const [quantity, setQuantity] = useState(0);
useEffect(()=>{
props.onChange(props.element, quantity);
}, [props.element, quantity]);
const onChange = (e) => {
setQuantity(parseInt(e.target.value));
e.preventDefault();
};
return (
<Form.Group>
<Form.Label>Quantity</Form.Label>
<InputGroup>
<Form.Control onChange={onChange} onKeyDown={(e)=>{e.preventDefault();}} type={"number"} value={quantity} min={0} max={props.remaining} aria-describedby="basic-addon1"/>
<InputGroup.Text id="basic-addon1">
{"/" + props.remaining}
</InputGroup.Text>
</InputGroup>
</Form.Group>
);
}
Any help in getting access to the values of the mapped QuantityForms using Refs is greatly appreciated. [1]: How target DOM with react useRef in map