Where can I place these react hooks? - reactjs

I had some hooks that I was using in my render of the code below - and they were working until I added a few useEffects. I am unceretain where to put these hooks to make them work again though - now I get the error "rendered more hooks than last time" -
The hooks I am trying to use are FormatDate and BandIcon. FormatDate gets data from props.post and BandIcon gets data from props.band. Can you help me figure out where to put these hooks so they work again?
I tried using them in the first useEffect by calling the hook to set a new part of state to hold that value... but that didnt work either.
import React, { useState, useEffect } from 'react'
import { Card, CardTitle, Badge, Button, CardFooter } from 'reactstrap'
import BandIcon from '../../../../uitls/BandIcon'
import FormatDate from '../../../../uitls/FormatDate'
import { Modal, ModalBody } from 'reactstrap'
import ReactMapGL, { Marker } from 'react-map-gl';
import { useAuth0 } from "../../../../react-auth0-spa";
let shouldUpdate = 0
let shouldUpdateStatus = 0
let shouldUpdateFavorites = 0
export default function ShowsPosts(props) {
const { user } = useAuth0();
const { post, band, _id, addRockOn, addFavorites, favorites } = props
const [ day, setDay ] = useState('')
const [ client, setClient ] = useState()
const [ approved, setApproved ] = useState('')
const [customQuotes, setCustomQuotes] = useState([])
const [modal, setModal] = useState(false);
const [ perfromanceDate, setPerformanceDate ] = useState('')
const [ venueAddress, setVenueAddress ] = useState([])
const [ viewPort, setViewport ] = useState();
const [ total, setTotal ] = useState(0);
const [ baseCost, setBaseCost ] = useState(0);
const { getTokenSilently } = useAuth0();
const [isUser, setIsUser ] = useState(null)
const [ rocks, setRocks ] = useState([])
const [ renderIcon, setRenderIcon ] = useState('')
useEffect(() => {
//Required Gig Details
post.details.map(detail => {
if(detail.title === "Performance Date"){
setPerformanceDate(detail.detail)
}
if(detail.title === "Venue Address"){
setVenueAddress(detail.detail)
}
if(detail.title === 'Base Cost'){
setBaseCost(detail.money)
}
return null
})
//Client
setClient(post.client)
let slicedDay = new Date(post.details.map(detail => {
if (detail.title === "Performance Date"){
return detail.detail
}else{
return null
}
})).toDateString().slice(0,3)
//Create Day Icon
switch (slicedDay){
case 'Mon':
setDay('monday.svg')
break;
case 'Tue':
setDay('tuesday.svg')
break;
case 'Wed':
setDay('wednesday.svg')
break;
case 'Thu':
setDay('thursday.svg')
break;
case 'Fri':
setDay('friday.svg')
break;
case 'Sat':
setDay('saturday.svg')
break;
default:
console.log('switch didnt work')
}
//Gig Status
setApproved(post.approved)
//Add Custom Qutoes - I added the return in the first part
post.details.filter(detail => {
if(detail.title !== "Performance Date" || detail.title !== "Base Cost" || detail.title !== "Venue Address"){
return setCustomQuotes(quotes => [...quotes, detail])
}else {
return null
}
})
//Set Total
setTotal(post.total)
setRocks(post.rockOn)
}, [post])
useEffect(() => {
if(shouldUpdate >= 1){
setViewport({
latitude: post.details.filter(detail => {
if(detail.title === "Venue Address"){
return detail.detail[2][1]
}else {
return null
}
})[0].detail[2][0] ,
longitude: post.details.filter(detail => {
if(detail.title === "Venue Address"){
return detail.detail[2][1]
}else {
return null
}
})[0].detail[2][1],
width: '100%',
height: 100,
zoom: 12,
})
}else {
shouldUpdate += 1
}
}, [venueAddress, post.details])
const saveBookingStatus = async (newStatus) => {
const token = await getTokenSilently();
try {
await fetch(`/api/autoquotegenerators/posts/${_id}/${post.postId}`, {
method: 'PUT',
headers: {
"Content-Type": "application/json; charset=UTF-8",
Authorization: `bearer ${token}`
},
body: JSON.stringify(
{
"approved": newStatus
}
)
})
} catch (error) {
console.log(error)
}
}
useEffect(() => {
if(user.sub.slice(6, user.sub.length) === band.userId){
setIsUser(true)
}else{
setIsUser(false)
}
}, [band, user])
const toggle = () => setModal(!modal);
if( !post || !band || !user || !rocks || !approved ){
console.log(post)
console.log(band)
console.log(user)
console.log(rocks)
console.log(approved)
return <div>...loading</div>
}
const handleRockOn = () => {
if(rocks.includes(user.sub.slice(6, user.sub.length))){
setRocks(rocks => [...rocks.filter(rock => { return rock !== user.sub.slice(6, user.sub.length)})])
addRockOn(post.postId, rocks.filter(rock => { return rock !== user.sub.slice(6, user.sub.length)}), props._id)
}else {
setRocks(rocks => [...rocks, user.sub.slice(6, user.sub.length)])
addRockOn(post.postId, rocks.concat(user.sub.slice(6, user.sub.length)), props._id)
}
}
const handleFavorites = () => {
addFavorites(user.sub.slice(6, user.sub.length), band)
}
return (
<Card color="light" className="my-1 d-flex flex-column justify-content-start">
<span className="d-flex flex-row align-self-start mx-2 mt-2 mb-1">
<img onClick={()=> {window.location.href=`/band/${_id}`}} src={BandIcon(band.bandGenre)} alt="Band Icon" style={{
width: "30px",
height: "30px",
cursor: 'pointer'
}}/>
<span className="h6 mt-2 mx-1">
<strong onClick={()=> {window.location.href=`/band/${_id}`}} style={{cursor: 'pointer'}}>{band.bandName}</strong> - {FormatDate(post.date)}
</span>
</span>
<Button
color="light"
id="dateCardPost"
onClick={toggle}
className="d-flex flex-row align-self-start p-4 mx-5 mt-1 mb-3 w-75"
style={{cursor: "pointer",
pointerEvents: isUser ? "auto" : "none" }}
>
<img src={`/calendarIcons/${day}`}
className="mr-2"
alt=""
style={{
width: "85px",
height: "85px",
}}/>
<Badge color="primary" className="align-self-start mx-1 mt-1" style={{
display: approved === 'pending' ? "block" : "none"
}}>?</Badge>
<Badge color="danger" className="align-self-start mx-1 mt-1" style={{
display: approved === 'false' ? "block" : "none"
}}>X</Badge>
<Badge color="success" className="align-self-start mx-1 mt-1" style={{
display: approved === 'true' ? "block" : "none"
}}>✓</Badge>
<CardTitle className="d-flex flex-column mx-1 align-items-start">
<span><strong>{band.bandName}'s</strong> Show</span>
<span>on <strong>{perfromanceDate.slice(4)}</strong></span>
<span>at <strong>{venueAddress[1]} </strong></span>
<span>
is {approved === 'pending' ? 'un-confirmed!' : null}
{approved === 'false' ? 'cancelled!' : null}
{approved === 'true' ? 'confirmed!' : null}
</span>
</CardTitle>
</Button>
<Modal isOpen={modal} toggle={toggle}>
<ReactMapGL
style={{zIndex: "2"}}
{...viewPort}
mapboxApiAccessToken={"pk.eyJ1Ijoibmlja2lzeW91cmZhbiIsImEiOiJjazh5azhjNjUxNzIwM21zZmdoZTBoM243In0.4ijWndTzChYeKo67PYSuAw"}
onViewportChange={viewport => setViewport(viewport)}
mapStyle="mapbox://styles/nickisyourfan/ck8ylgfk90kcb1iqoemkes76u"
>
<Marker
latitude={post.details.filter(detail => {
if(detail.title === "Venue Address"){
return detail.detail[2][1]
}else {
return null
}
})[0].detail[2][0]}
longitude={post.details.filter(detail => {
if(detail.title === "Venue Address"){
return detail.detail[2][1]
}else {
return null
}
})[0].detail[2][1]}
offsetLeft={-25}
offsetTop={-20}>
<img src={BandIcon(band.bandGenre)} alt="Band Icon" style={{
width: "30px",
height: "30px",
}}/>
</Marker>
</ReactMapGL>
<ModalBody className="d-flex flex-column align-items-start">
<Card color="light" className="d-flex flex-column py-3 w-75 align-self-center justify-content-center align-items-center h5">{band.bandName}</Card>
<Card color="light" className="d-flex flex-column py-2 w-75 align-self-center justify-content-center align-items-center h6">
<span className="h6">{perfromanceDate}</span>
<span><strong>Venue: </strong>{venueAddress[1]}</span>
<span><strong>Address: </strong>{venueAddress[0]}</span>
</Card>
<Card color="light" className="d-flex flex-column py-2 w-75 align-self-center justify-content-center align-items-center h6">
<span><strong>Client: </strong>{client}</span>
<span><strong>Base Cost: </strong>${baseCost}</span>
{customQuotes.map(quote => {
if(quote.title !== 'Venue Address' || quote.title !== 'Base Cost' || quote.title !== 'Performance Date'){
return null
}else {
return <span key={quote.chargeId}><strong>{quote.title}: </strong>{quote.detail} ${quote.money}</span>
}
})}
</Card>
<Card color="light" className="d-flex flex-column py-2 w-75 align-self-center justify-content-center align-items-center h6">
<span><strong>Total: </strong>${total}</span>
</Card>
</ModalBody>
<Button
id="cancelBookingButton"
onMouseEnter={() => {
if(approved === 'true'){
document.getElementById('cancelBookingButton').innerHTML = 'Cancel Booking?'}
}}
onMouseLeave={() => {
if(approved === 'true'){
document.getElementById('cancelBookingButton').innerHTML = 'Booking Approved'
}
}}
onClick={() => {
setApproved('false')
saveBookingStatus('false')
}}
className="w-100 rounded-0"
color={approved === 'pending' ? 'danger' : 'success'}
style={{
display: approved === 'pending' || approved === 'true' ? 'block' : 'none',
}}>
{approved === 'pending' ? 'Decline Booking' : 'Booking Approved'}
</Button>
<Button
id="approveBookingButton"
onMouseEnter={() => {
if(approved === 'false'){
document.getElementById('approveBookingButton').innerHTML = 'Re-Confirm Booking?'
}
}}
onMouseLeave={() => {
if(approved === 'false'){
document.getElementById('approveBookingButton').innerHTML = 'Booking Cancelled'
}
}}
onClick={() => {
setApproved('approved')
saveBookingStatus('approved')
}}
className="w-100 rounded-0"
color={approved === 'false' ? 'danger' : 'success'}
style={{
display: approved === 'false' || approved === 'pending' ? 'block' : 'none',
}}>
{approved === 'pending' ? 'Approve Booking' : 'Booking Cancelled'}
</Button>
</Modal>
<CardFooter className="d-flex flex-row justfiy-content-between p-0">
<Button onClick={handleRockOn} color={rocks.includes(user.sub.slice(6, user.sub.length)) ? 'light active' : 'light'} className="d-flex w-50 h-100 rounded-0 justify-content-center shadow-none" >
<img src='/Rock-On.svg' style={{width: '27px', height: '27px'}} className="mr-2"/>
<span className="ml-2">{rocks.length}</span>
</Button>
<Button onClick={handleFavorites} color={favorites.includes(user.sub.slice(6, user.sub.length)) ? 'light active' : 'light'} className='w-50 h-100 rounded-0' style={{boxShadow: 'none'}}>
<img src='/FavoriteBand.svg' style={{width: '25px', height: '25px'}} />
</Button>
</CardFooter>
</Card>
)
}

It seems you have lots of logic inside one component. I'll suggest beginning with splitting pieces of related logic into custom hooks in separate so you have less code inside your components and can you can find where are the errors while you are extracting them.
Implementation example:
function useViewport(venueAddress, postDetails) {
const [viewPort, setViewport] = useState();
useEffect(() => {
if (shouldUpdate >= 1) {
setViewport({
latitude: post.details.filter((detail) => {
if (detail.title === 'Venue Address') {
return detail.detail[2][1];
} else {
return null;
}
})[0].detail[2][0],
longitude: post.details.filter((detail) => {
if (detail.title === 'Venue Address') {
return detail.detail[2][1];
} else {
return null;
}
})[0].detail[2][1],
width: '100%',
height: 100,
zoom: 12,
});
} else {
shouldUpdate += 1;
}
}, [venueAddress, postDetails]);
return viewPort;
}
Inside your ShowsPosts component:
useViewport(venueAddress, post.details);

Related

The initial chart before the chart data changes automatically in reactjs

I'm having trouble here when I want to put chart data at the beginning.
So, before the user clicks on the name "province", the chart will first display provincial data.
Then, the user clicks on the province name, the chart will change the previous chart data to city chart data. like this
However, I am stuck here, displaying the initial chart data, namely provincial chart data.
Please help me to solve my current problem, that is, displaying province charts before changing to city charts. Thank you
My Code
import React, { useState, useEffect, useRef } from "react";
import {
Accordion,
AccordionItem,
AccordionItemHeading,
AccordionItemButton,
AccordionItemPanel,
} from "react-accessible-accordion";
import { MdKeyboardArrowDown } from "react-icons/md";
import {
getStreetDallProvinsi,
// getStreetImageDallProvinsi,
getStreetallKota,
getStreetallKecamatan,
getStreetallKelurahan,
} from "../../../service/building";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
} from "chart.js";
import { Bar } from "react-chartjs-2";
import SearchComponent from "./SearchPoi";
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
);
const Data = () => {
const [filterdata, setFilterdata] = useState([]);
const [query, setQuery] = useState("");
const [dataProvinsi, setDataProvinsi] = useState([]);
const [dataKota, setDataKota] = useState([]);
const [dataKecamatan, setDataKecamatan] = useState([]);
const [dataKelurahan, setDataKelurahan] = useState([]);
// const [dataImageProvinsi, setDataImageProvinsi] = useState([]);
const [dataChart, setDataChart] = useState();
const [isLoading, setIsLoading] = useState(false);
const [isLoadingKota, setIsLoadingKota] = useState(false);
const [isLoadingKecamatan, setIsLoadingKecamatan] = useState(false);
const provinsiRef = useRef([]);
const kotaRef = useRef([]);
const kecamatanRef = useRef([]);
const getDataAllProvinsi = () => {
setIsLoading(true);
getStreetDallProvinsi()
.then((resolve) => {
setDataProvinsi(resolve);
setFilterdata(resolve);
console.log(resolve);
})
.catch((reject) => {
console.log(reject);
})
.finally(setIsLoading(false));
};
const handlesearch = (event) => {
const getSearch = event.target.value;
if (getSearch.length > 0) {
const searchdata = dataProvinsi.filter((item) =>
item.provinsi.toLowerCase().includes(event.target.value.toLowerCase())
);
setDataProvinsi(searchdata);
} else {
setDataProvinsi(filterdata);
}
setQuery(getSearch);
};
// const getDataImageAllProvinsi = () => {
// setIsLoading(true);
// getStreetImageDallProvinsi()
// .then((resolve) => {
// setDataImageProvinsi(resolve);
// console.log();
// })
// .catch((reject) => {
// console.log(reject);
// })
// .finally(setIsLoading(false));
// };
const handleProvinsi = async (index) => {
try {
const provinsi = provinsiRef.current[index].dataset.prov;
setIsLoading(true);
const result = await getStreetallKota(provinsi);
setDataKota(result);
setDataChart(state.data.dataKota);
console.log(result);
} catch (error) {
console.log("salah")
} finally {
setIsLoading(false);
}
};
const handleKota = async (provinsi, index) => {
try {
const kota = kotaRef.current[index].dataset.city;
setIsLoadingKota(true);
const result = await getStreetallKecamatan(provinsi, kota);
setDataKecamatan(result);
setDataChart(state.data.dataKecamatan);
console.log(result);
} catch (error) {
console.log("salah")
} finally {
setIsLoadingKota(false);
}
};
const handleKecamatan = async (provinsi, kota, index) => {
try {
const kecamatan = kecamatanRef.current[index].dataset.camat;
setIsLoadingKecamatan(true);
const result = await getStreetallKelurahan(provinsi, kota, kecamatan);
setDataKelurahan(result);
console.log(result);
} catch (error) {
console.log("salah")
console.log(error)
} finally {
setIsLoadingKecamatan(false);
}
};
useEffect(() => {
getDataAllProvinsi();
// getDataImageAllProvinsi();
}, [dataChart]);
const colorCode = "#0066FF";
const colorFont = "#8E9093";
const state = {
data: {
dataProv: {
labels: dataProvinsi.map((o) => o.provinsi),
datasets: [
{
fill: true,
label: null,
backgroundColor: colorCode,
borderColor: colorCode,
borderWidth: 2,
borderRadius: 12,
data: dataProvinsi.map((o) => o.total_street),
},
],
},
dataKota: {
labels: dataKota.map((o) => o.kota),
datasets: [
{
fill: true,
label: null,
backgroundColor: colorCode,
borderColor: colorCode,
borderWidth: 2,
borderRadius: 12,
data: dataKota.map((o) => o.total_street),
},
],
},
dataKecamatan: {
labels: dataKecamatan.map((o) => o.kecamatan),
datasets: [
{
fill: true,
label: null,
backgroundColor: colorCode,
borderColor: colorCode,
borderWidth: 2,
borderRadius: 12,
data: dataKecamatan.map((o) => o.total_street),
},
],
},
},
options: {
plugins: {
legend: {
display: false,
labels: {
font: {
color: colorFont,
},
},
},
},
scales: {
x: {
grid: {
display: false,
},
beginAtZero: false,
ticks: {
color: colorFont,
},
},
y: {
grid: {
display: false,
},
beginAtZero: true,
ticks: {
color: colorFont,
},
},
},
},
};
const plugins = [
{
beforeDraw: function (chart) {
if (chart.chartArea) {
let ctx = chart.ctx;
let chartArea = chart.chartArea;
let barArray = chart.getDatasetMeta(0).data;
ctx.fillStyle = "#B2D1FF85";
for (let i = 0; i < barArray.length; i++) {
const { x, width } = barArray[i];
ctx.fillRect(
x - width / 2,
chartArea.top,
width,
chartArea.bottom - chartArea.top
);
}
}
},
},
];
return (
<>
<div className="mx-auto mt-8 w-[70rem] h-[32rem] bg-white px-5 py-3 md:px-8 md:py-5 rounded-xl drop-shadow-xl">
<h1 className="font-bold text-lg mb-4">Diagram Data</h1>
<Bar
type={"bar"}
height={120}
data={state.data.dataKota}
options={state.options}
plugins={plugins}
/>
</div>
<div className="mx-auto my-8 w-[70rem] bg-white px-5 py-3 md:px-8 md:py-5 rounded-md drop-shadow-xl">
<SearchComponent value={query} onChange={(e) => handlesearch(e)} />
<div className="flex justify-between mt-6">
<h3 className="font-bold">Nama Daerah</h3>
<div className="flex gap-8">
<h3 className="font-bold">TOTAL IMAGE</h3>
<h3 className="font-bold">TOTAL LABELLING</h3>
</div>
</div>
<Accordion allowZeroExpanded>
{dataProvinsi.map((provinsi, index) => (
<AccordionItem className="p-1" key={index}>
<AccordionItemHeading
onClick={() => {
handleProvinsi(index);
}}
>
<AccordionItemButton>
<div className="w-full inline-flex justify-between items-center">
<div className="inline-flex items-center gap-2">
<div>
<MdKeyboardArrowDown size={20} />
</div>
<div
ref={(ref) => provinsiRef.current.push(ref)}
data-prov={provinsi?.provinsi}
>
{provinsi?.provinsi}
</div>
</div>
<div>{provinsi?.total_street}</div>
</div>
</AccordionItemButton>
</AccordionItemHeading>
<AccordionItemPanel className="ml-4">
<Accordion className="flex flex-col gap-2" allowZeroExpanded>
{isLoading
? "Loading ... "
: dataKota.map((kota, index) => (
<AccordionItem className="p-1" key={kota?.id}>
<AccordionItemHeading
onClick={() => {
handleKota(provinsi?.provinsi, index);
}}
>
<AccordionItemButton>
<div className="w-full inline-flex justify-between items-center">
<div className="inline-flex items-center gap-2">
<div>
<MdKeyboardArrowDown size={20} />
</div>
<div
ref={(ref) => kotaRef.current.push(ref)}
data-city={kota?.kota}
>
{kota?.kota}
</div>
</div>
<div>{kota?.total_street}</div>
</div>
</AccordionItemButton>
</AccordionItemHeading>
<AccordionItemPanel className="ml-8">
<Accordion
className="flex flex-col gap-2"
allowZeroExpanded
>
{isLoadingKota
? "Loading..."
: dataKecamatan.map((kecamatan, index) => (
<AccordionItem
className="p-1"
key={kecamatan?.id}
>
<AccordionItemHeading
onClick={() => {
handleKecamatan(
provinsi?.provinsi, kota?.kota,
index
);
}}
>
<AccordionItemButton>
<div className="w-full inline-flex justify-between items-center">
<div className="inline-flex items-center gap-2">
<div>
<MdKeyboardArrowDown
size={20}
/>
</div>
<div
ref={(ref) => kecamatanRef.current.push(ref)}
data-camat={kecamatan?.kecamatan}
>
{kecamatan?.kecamatan}
</div>
</div>
<div>{kecamatan?.total_street}</div>
</div>
</AccordionItemButton>
</AccordionItemHeading>
<AccordionItemPanel className="ml-12">
<Accordion
className="flex flex-col gap-2"
allowZeroExpanded
>
{isLoadingKecamatan
? "Loading..."
: dataKelurahan.map(
(item, index) => (
<AccordionItem
className="p-1"
key={index}
>
<AccordionItemHeading>
<AccordionItemButton>
<div className="w-full inline-flex justify-between items-center">
<div className="inline-flex items-center gap-2">
<div>
<MdKeyboardArrowDown
size={20}
/>
</div>
<div>
{item?.kelurahan}
</div>
</div>
<div>
{item?.total_street}
</div>
</div>
</AccordionItemButton>
</AccordionItemHeading>
</AccordionItem>
)
)}
</Accordion>
</AccordionItemPanel>
</AccordionItem>
))}
</Accordion>
</AccordionItemPanel>
</AccordionItem>
))}
</Accordion>
</AccordionItemPanel>
</AccordionItem>
))}
</Accordion>
</div>
</>
);
};
export default Data;

moving cards with react-sortablejs

I wanted to try out Strapis guide to create a Trello Clone
https://strapi.io/blog/build-a-trello-clone-application-with-react-and-strapi-1
But right now I'm having a bit of an issue moving my cards...
The cards do show up when moving them but for some reason it doesn't seem to be switching the "state".
this is what my Board.js looks like:
import { ReactSortable } from "react-sortablejs";
import { useState, useEffect } from "react";
import axios from "axios";
const Board = () => {
const [tasks, settasks] = useState([]);
const [drafts, setdrafts] = useState([]);
const [progresstasks, setprogresstasks] = useState([]);
const [approvals, setapprovals] = useState([]);
const [finished, setfinished] = useState([]);
const [onholds, setonholds] = useState([]);
const [newTask, setnewTask] = useState("");
const addTask = async () => {
if(newTask !== ""){
let res = await axios
.post("http://localhost:1337/api/tasks", {
data :{
state: "draft",
Description: newTask,
}
})
.catch((err) => alert("Error occured"));
}
await getTasks();
setnewTask("");
};
const getTasks = async () => {
let Tasks = await axios.get("http://localhost:1337/api/tasks?populate=*");
// return;
settasks(Tasks.data.data);
// For Drafts
let Drafts = tasks.filter((res) => {
return res.attributes.state=== "draft";
});
setdrafts(Drafts);
// For Progress
let Progress = tasks.filter((res) => {
return res.attributes.state === "progress";
});
setprogresstasks(Progress);
// For Finished
let Finished = tasks.filter((res) => {
return res.attributes.state === "finished";
});
setfinished(Finished);
// For Approval
let Approval = tasks.filter((res) => {
return res.attributes.state === "approval";
});
setapprovals(Approval);
// For Onhold
let Onhold = tasks.filter((res) => {
return res.attributes.state=== "onhold";
});
setonholds(Onhold);
};
const getCustomers = async () => {
let Customers = await axios.get("http://localhost:1337/api/customers?populate=*");
}
useEffect(() => {
getTasks();
getCustomers();
});
return (
<>
<div className="container mt-5 mb-5">
<div
className="row"
style={{
height: "80vh",
}}
>
<div className="col mx-2 px-2 py-3 bg-light border rounded">
<h6>Entwurf</h6>
<div
style={{
minHeight: "500px",
}}
>
<ReactSortable
list={tasks}
setList={setdrafts}
groupp={"group-1"}
group={{ name: "group-1", put: true }}
>
{tasks.filter((task) => task.attributes.state === "draft")
.map((filteredTask) => (
<div
className="card p-3 border rounded mt-2"
key={filteredTask.id}
>
{filteredTask.attributes.Description}
</div>
))}
</ReactSortable>
</div>
<div>
<textarea
rows={"1"}
cols={30}
style={{ float: "left", borderBlockColor: "#007bff" }}
value={newTask}
onChange={(event) => setnewTask(event.target.value)}
></textarea>
<button
type="button"
style={{ float: "right", marginTop: "2px" }}
class="btn btn-primary btn-sm"
onClick={addTask}
>
Add Task
</button>
</div>
</div>
<div className="col mx-2 px-2 py-3 bg-light border rounded">
<h6>In Bearbeitung</h6>
<div
style={{
minHeight: "500px",
}}
>
<ReactSortable
list={tasks}
setList={setprogresstasks}
grouppp={"group-1"}
// group={{ name: "group-1", put: true }}
>
{tasks.filter((task) => task.attributes.state === "progress")
.map((filteredTask) => (
<div
className="card p-3 border rounded mt-2"
key={filteredTask.id}
>
{filteredTask.attributes.Description}
</div>
))}
</ReactSortable>
</div>
</div>
<div className="col mx-2 px-2 py-3 bg-light border rounded">
<h6>Fertig</h6>
<div
style={{
minHeight: "500px",
}}
>
<ReactSortable
list={tasks}
setList={setfinished}
groupppp={"group-1"}
// group={{ name: "group-1", put: true }}
>
{tasks.filter((task) => task.attributes.state === "finished")
.map((filteredTask) => (
<div
className="card p-3 border rounded mt-2"
key={filteredTask.id}
>
{filteredTask.attributes.Description}
</div>
))}
</ReactSortable>
</div>
</div>
<div className="col mx-2 px-2 py-3 bg-light border rounded">
<h6>On-Hold</h6>
<div
style={{
minHeight: "500px",
}}
>
<ReactSortable
list={tasks}
setList={setonholds}
grouppppp={"group-1"}
// group={{ name: "group-1", put: true }}
>
{tasks.filter((task) => task.attributes.state === "onhold")
.map((filteredTask) => (
<div
className="card p-3 border rounded mt-2"
key={filteredTask.id}
>
{filteredTask.attributes.Description}
</div>
))}
</ReactSortable>
</div>
</div>
<div className="col mx-2 px-2 py-3 bg-light border rounded">
<h6>Wartet auf Freigabe</h6>
<div
style={{
minHeight: "500px",
}}
>
<ReactSortable
list={tasks}
setList={setapprovals}
groupppppp={"group-1"}
// group={{ name: "group-1", put: true }}
>
{tasks.filter((task) => task.attributes.state === "approval")
.map((filteredTask) => (
<div
className="card p-3 border rounded mt-2"
key={filteredTask.id}
>
{filteredTask.attributes.Description}
</div>
))}
</ReactSortable>
</div>
</div>
</div>
</div>
</>
);
};
export default Board;
Is there something I'm missing like executing a function when moving the cards?

Reset states of a component when it is closed

I have created a MERN application in which on dashboard when a button is clicked a modal box opens which contains some inputs and some options to be selected which are handled using react state hooks. I want when I close modal box the value in it should be reset to default one and when i reopen it all the options should reset to default value
Here is my modal box code
import React, { useState, useContext, useEffect } from "react";
import { UserContext } from "./UserContext";
function SplitModal({
setsplitmodal,
cost,
list,
listobj,
setlistobj,
equal,
setEqual,
payer,
setPayer,
part,
setPart,
setM,
}) {
const [method, setMethod] = useState(true);
const [split, setsplit] = useState(true);
const [owe, setowe] = useState(true);
const [owes, setowes] = useState(true);
const [click, setClick] = useState(false);
const [amount, setAmount] = useState();
const [total, setTotal] = useState(0);
const { user, userfriend } = useContext(UserContext);
console.log(user, "user hu darta koni", user.name);
console.log(listobj);
useEffect(() => {
if (equal === "unequally") {
const _listobj = { ...listobj };
Object.keys(listobj).map((f) => {
_listobj[f] = 0;
});
setlistobj(_listobj);
document.getElementById("InputId").value = "";
console.log(_listobj, "listobjsehu");
}
}, [list, cost]);
const func1 = () => {
setM(false);
setEqual("unequally");
setMethod(false);
const _list = { ...listobj };
_list[list[0]] = -cost;
_list[list[1]] = cost;
setlistobj(_list);
setowe(false);
setowes(true);
setPayer(list[1]);
setPart(`(You owe ${list[1]} ₹${cost})`);
};
const func2 = () => {
setM(false);
setEqual("unequally");
setMethod(false);
const _list = { ...listobj };
const b = _list[list[0]];
_list[list[0]] = +cost;
_list[list[1]] = -cost;
setlistobj(_list);
setPayer(list[0]);
setowe(true);
setowes(false);
setPart(`(${list[1]} owes you ₹${cost})`);
// console.log(owe, owes, click);
};
const distriequal = () => {
setM(true);
// setowe(true);
// setowes(true);
setPart(`(₹${(cost / list.length).toFixed(2)}/person)`);
setMethod(true);
setEqual("equally");
setTotal(0);
const _list = { ...listobj };
list.map((f) => {
if (f === payer) {
_list[f] = (cost - cost / list.length).toFixed(2);
} else {
_list[f] = -(cost / list.length).toFixed(2);
}
setlistobj(_list);
});
};
// console.log(listobj.exp[list[1]], listobj);
const distriamount = (e, i) => {
if (e.key === "Backspace") setM(true);
if (parseInt(e.target.value) > cost) setAmount("err");
else setAmount("");
// console.log( a.replace(a,e.targetvalue));
const _list = { ...listobj };
if (list[i] === payer) {
// _list[list[i]] = e.target.value;
// setOwner(e.target.value);
_list[payer] = parseInt(cost - e.target.value);
} else {
_list[list[i]] = -e.target.value;
}
setlistobj(_list);
if (listobj[user.name] > 0)
setPart(`You get back ₹${Math.abs(_list[user.name])}`);
else if (listobj[user.name] < 0)
setPart(`You owe ₹${Math.abs(_list[user.name])}`);
else setPart(`You owe nothing`);
};
// useEffect(() => {
// Object.keys(listobj).map((f) => {
// if (f === user.name) {
// console.log("nmnm");
// setTotal(total + owner);
// } else setTotal(total + Math.abs(listobj[f]));
// });
// }, [listobj]);
console.log(listobj, list);
return (
<div>
<div className="splitmodal">
<div
style={{
backgroundColor: "#1cc29f",
border: "1px solid #eeeeee",
padding: "5px",
display: "flex",
borderRadius: "10px 10px 0px 0px",
color: "white",
}}
>
<h5 style={{ marginLeft: "100px" }}>Choose Payer</h5>
<button
style={{ position: "absolute", right: "10px" }}
onClick={() => {
setsplitmodal(false);
}}
>
<i class="fas fa-times" />
</button>
</div>
{list.length === 2 ? (
<div className="bg-white splitmodal-main1">
<button
onClick={() => {
setMethod(true);
setM(true);
setClick();
setowe(true);
setowes(true);
}}
>
Split the expense
</button>
<button
onClick={() => {
{
setClick("owe");
return owe ? func1() : null;
}
}}
className={click === "owe" ? "click" : null}
>
You owe {list[1]} ₹{cost}
</button>
<button
className="mb-2"
onClick={() => {
{
setClick("owes");
return owes ? func2() : null;
}
}}
className={click === "owes" ? "click" : null}
>
{list[1]} owes you ₹{cost}
</button>
</div>
) : null}
{method ? (
<div className="splitmodal-main2">
<hr style={{ margin: "10px" }} />
<div className="flex justify-content-center">
<button
style={{
border: "1px solid #ccc",
borderRadius: "5px 0px 0px 5px",
}}
className={equal === "equally" ? "select" : "deselect"}
onClick={() => {
distriequal();
}}
>
Split equally
</button>
<button
style={{
border: "1px solid #ccc",
borderRadius: "0px 5px 5px 0px",
}}
className={equal === "unequally" ? "select" : "deselect"}
onClick={() => {
setEqual("unequally");
}}
>
Split by amounts
</button>
</div>
{equal === "equally" ? (
<div>
<div className="splitmodal-main3">
<h5 className="mt-2 ml-3">Split equally</h5>
<ul
style={{
display: "flex",
flexDirection: "column",
marginLeft: "10px",
}}
>
{list.map((f) => {
return (
<li className="flex align-items-center m-2">
<img
src="https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-grey47-50px.png"
alt=""
/>
<span className="ml-2 font-bold">{f}</span>
<span className="absolute right-10 ">
₹{cost ? (cost / list.length).toFixed(2) : 0.0}
</span>
</li>
);
})}
</ul>
</div>
</div>
) : (
<div>
<div className="splitmodal-main3">
<h5 className="mt-2 ml-3">Split by amounts</h5>
<ul
style={{
display: "flex",
flexDirection: "column",
marginLeft: "10px",
}}
>
{list.map((f, i) => {
return (
<li key={i} className="flex align-items-center m-2">
<img
src="https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-grey47-50px.png"
alt=""
/>
<span className="ml-2 font-bold">{f}</span>
<span className="absolute right-5 ">
<span
style={{
backgroundColor: "#EEEEEE",
paddingLeft: "14px",
paddingRight: "14px",
border: "1px solid #ccc",
borderRadius: "4px 0px 0px 4px",
}}
>
₹
</span>
<input
type="number"
// value={Math.abs(listobj[f])}
id="InputId"
style={{
width: "60px",
border: "1px solid #ccc",
borderRadius: "0px 4px 4px 0px",
height: "23.33px",
}}
className={
amount === "err" ? "text-red-500" : null
}
onChange={(e) => {
distriamount(e, i);
}}
/>
</span>
</li>
);
})}
</ul>
</div>
{/* <div className="mt-2 ml-3">
<h5>Total:</h5>
<span className="absolute right-10 bottom-0 ">₹{total}</span>
</div> */}
</div>
)}
</div>
) : null}
</div>
</div>
);
}
export default SplitModal;
Please help me solving this
As a workaround you can write a new useEffect() that reset all the value at the loading of your component, something like :
useEffect(() => {
setMethod(true);
setsplit(true);
setowe(true);
setowes(true);
setClick(false);
setAmount();
setTotal(0);
}, []);
We don't actually need a separate effect to perform the cleanup. useEffect is designed to keep it together.
Learn more on: https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup
useEffect(() => {
// your other codes
return function reset() {
setMethod(true);
setsplit(true);
setowe(true);
setowes(true);
setClick(false);
setAmount(0);
setTotal(0);
}
}, []);

Why my props are undefined when sending to components?

I have a table in my project and I have an edit / view / add page that I can access from this table. My goal is to send the clicked data to the other component without any problem, but no matter how hard I try, I get an undefined error and the project is broken. I would be glad if you could help.
I am sharing my codes from parent to child component
Table page.
import React, { useState, useEffect, useCallback, useMemo } from "react";
import ManagementTable from '../components/ManagementTable'
import {
getApps,
updateStopRisk,
countLiveCountry,
updateAppShow,
deleteApp,
} from "../api/apiCalls";
import VisibilityIcon from "#material-ui/icons/Visibility";
import DeleteIcon from "#material-ui/icons/Delete";
import EditIcon from "#material-ui/icons/Edit";
import Switch from "#material-ui/core/Switch";
import DeleteModal from "../components/DeleteModal";
import { Link } from "react-router-dom";
const Management = () => {
const [apps, setApps] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
const [currentApp, setCurrentApp] = useState("");
const [appID, setAppID] = useState(0);
const fetchData = useCallback(async () => {
const { data: appsResponse } = await getApps();
const countLiveCountries = await fetchLiveCountriesForApps(appsResponse);
setApps(
appsResponse.map((app, idx) => ({
...app,
countLiveCountry: countLiveCountries[idx],
}))
);
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);
const fetchLiveCountriesForApps = async (appwLive) => {
const countLiveCountries = await Promise.all(
appwLive.map((app) => countLiveCountry(app.appID))
);
return countLiveCountries.map(({ data: liveCountries }) => liveCountries);
};
const removeApp = async () => {
await deleteApp(appID);
setModalVisible(false);
fetchData();
};
const onClickCancel = () => {
setModalVisible(false);
};
const columns = useMemo(() => [
{
Header: "Application Name",
accessor: "app_name",
},
{
Header: "Business Area",
accessor: "businessarea.businessarea_name",
},
{
Header: "Live Plants",
accessor: "countLiveCountry",
},
{
Header: "Line Stop Risk",
accessor: "app_stoprisk",
Cell: ({ row: { original } }) => {
const changeCheck = async (id) => {
await updateStopRisk(id);
fetchData();
};
return (
<input
checked={original.app_stoprisk}
onClick={() => {
changeCheck(original.appID);
}}
id="appStopRisk"
type="checkbox"
style={{ width: 18, height: 18, marginTop: 5 }}
/>
)
},
sortType: (a, b, id) => {
if (a.original[id] > b.original[id]) return -1;
if (b.original[id] > a.original[id]) return 1;
},
},
{
Header: "Actions",
Cell: ({ row: { original } }) => {
const changeTrack = async (id) => {
await updateAppShow(id);
fetchData();
};
return (
<>
<Link
className="btn btn-manage-link btn-sm col-2"
to={{
pathname: `/management/${original.app_name}`,
mode: "view",
id: original.appID
}}
>
<VisibilityIcon></VisibilityIcon>
</Link>
<Link
to={{
pathname: `/management/${original.app_name}`,
mode: "edit",
id: original.appID
}}
className="btn btn-manage-link btn-sm col-2"
>
<EditIcon></EditIcon>
</Link>
<button
onClick={() => {
setModalVisible(true);
setCurrentApp(original.app_name);
setAppID(original.appID);
}}
className="btn btn-manage-link btn-sm col-3"
>
<DeleteIcon></DeleteIcon>
</button>
<Switch
onClick={() => changeTrack(original.appID)}
checked={original.app_show}
className="col-3"
></Switch>
</>
)
},
},
],
[fetchData]
);
return (
<div className="container">
<h2 style={{ float: "left", font: "bold" }}>Management</h2>
<div style={{ float: "right" }}>
<Link className="btn btn-danger btn-sm" to={{ pathname: `/management/add`, mode: "add" }}>
Add New App
</Link>
<Link className="btn btn-danger btn-sm ml-3" exact to="/management/plants">
Plant Management
</Link>
</div>
<ManagementTable columns={columns} data={apps} />
<DeleteModal
message={<strong>{currentApp}</strong>}
variety="app"
onClickCancel={onClickCancel}
onClickOk={removeApp}
visible={modalVisible}
/>
</div>
);
};
export default Management;
The page where I transfer the props.
import React, { useState, useEffect } from "react";
import Accordion from "../components/Accordion";
import Details from '../components/Details'
import {
getByIdApps,
} from "../api/apiCalls";
const ApplicationManagement = (props) => {
const [appById, setAppById] = useState([]);
const { id } = props.location;
const [selectOption, setSelectOption] = useState('add')
useEffect(() => {
getData();
getMode();
}, [])
const getData = async () => {
console.log(props.location.id)
if (props.location.id) {
await getByIdApps(props.location.id).then((response) => setAppById(response.data))
console.log(appById)
console.log(props)
}
else {
setSelectOption('add')
}
}
const getMode = () => props.location.mode ? setSelectOption(props.location.mode) : setSelectOption('add')
const handleOptionChange = (event) => {
console.log(event.target.value)
setSelectOption(event.target.value)
}
return (
<>
<div style={{ margin: 20 }}>
<h1>
{appById.app_shortcode} - {appById.app_fullname}
</h1>
<div className="float-right mb-auto">
<label><input type="radio" value="view" checked={selectOption === 'view'} onChange={handleOptionChange} />View</label>
<label> <input type="radio" value="add" checked={selectOption === 'add'} onChange={handleOptionChange} />Add</label>
<label> <input type="radio" value="edit" checked={selectOption === 'edit'} onChange={handleOptionChange} />Edit</label>
</div>
<br></br>
<div style={{ marginLeft: 50, marginRight: 50 }} >
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Links</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Factory Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Issues Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Middleware Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
</div>)
{selectOption === 'add' ? (
<div>
Add Mode
</div>
) : selectOption === 'view' ? (<div>View Mode</div>) : (<div>eidt</div>)}
</div>
</>
);
};
export default ApplicationManagement;
and the section where the details are kept on the ApplicationManagement page (My code is quite long, I just share the problem part.)
import React, { useState, useEffect } from 'react'
import axios from "axios";
import {
getResponsibleTeams,
getBusinessAreas
} from '../api/apiCalls'
const Details = (props) => {
const [rTeams, setrTeams] = useState([]);
const [bAreas, setbAreas] = useState([]);
const { data } = props;
useEffect(() => {
async function fetchData() {
const getrTeams = await getResponsibleTeams();
const getbAreas = await getBusinessAreas();
axios.all([getrTeams, getbAreas]).then(
axios.spread((...allData) => {
const allrTeams = allData[0].data;
const allbAreas = allData[1].data;
setrTeams(allrTeams);
setbAreas(allbAreas);
})
);
}
fetchData();
}, []);
return (
<div>
<div
style={{
float: "left",
width: 1350,
height: 340,
}}
>
<div className="form-group">
<label style={{ float: "left" }} htmlFor="appFullName">
Frontend:{" "}
</label>
<input
id="appFullName"
type="text"
class="form-control"
placeholder="dsfdsdsf"
value={data.frontend.frontend_name} // error here
//onChange={handleInputChange}
name="appShortCode"
style={{ width: 400, marginLeft: 150 }}
/>
</div>
</div>
</div>
)
}
export default Details;
Later I realized that using asynchronous functions caused some problems. I came up with a solution to this and the problem was solved.
Error Code Here :
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>
and the solution to the problem
{appById &&
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>}

Update the input value from one component in an other on runtime

I have a NotificationStepper Component which gets inputs from user, I need to update this input value in run time in another component named TabComponent. Both of the components are child components of SendNotification Component. How can i achieve that in reactjs.
EDIT
NotificationStepper.js
const styles = {
transparentBar: {
backgroundColor: 'transparent !important',
boxShadow: 'none',
paddingTop: '25px',
color: '#FFFFFF'
}
};
const useStyles = makeStyles((theme: Theme) =>
createStyles({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}),
);
function getSteps() {
return ['Create', 'Audience', 'Timing'];
}
function getStepContent(step, $this) {
switch (step) {
case 0:
return (
<div className="row">
<CardBox styleName="col-lg-12"
heading="">
<form className="row" noValidate autoComplete="off" style={{"flex-wrap":"no-wrap", "flex-direction": "column" }}>
<div className="col-md-12 col-12">
<TextField
id="campaign_name"
label="Campaign Name"
value={$this.state.name}
onChange={$this.handleChange('name')}
margin="normal"
fullWidth
/>
</div>
</form>
</CardBox>
</div>
);
default:
return 'Unknown step';
}
}
class NotificationStepper extends React.Component {
state = {
activeStep: 0,
name: '',
};
handleChange = name => event => {
this.setState({
[name]: event.target.value,
});
};
handleNext = () => {
this.setState({
activeStep: this.state.activeStep + 1,
});
};
handleBack = () => {
this.setState({
activeStep: this.state.activeStep - 1,
});
};
handleReset = () => {
this.setState({
activeStep: 0,
});
};
render() {
const steps = getSteps();
const {activeStep} = this.state;
return (
<div className="col-xl-12 col-lg-12 col-md-7 col-12">
<Stepper className="MuiPaper-root-custom" activeStep={activeStep} orientation="vertical">
{steps.map((label, index) => {
return (
<Step key={label}>
<StepLabel>{label}</StepLabel>
<StepContent className="pb-3">
<Typography>{getStepContent(index, this)}</Typography>
<div className="mt-2">
<div>
<Button
disabled={activeStep === 0}
onClick={this.handleBack}
className="jr-btn"
>
Back
</Button>
<Button
variant="contained"
color="primary"
onClick={this.handleNext}
className="jr-btn"
>
{activeStep === steps.length - 1 ? 'Finish' : 'Next'}
</Button>
</div>
</div>
</StepContent>
</Step>
);
})}
</Stepper>
{activeStep === steps.length && (
<Paper square elevation={0} className="p-2">
<Typography>All steps completed - you"re finished</Typography>
<Button onClick={this.handleReset} className="jr-btn">
Reset
</Button>
</Paper>
)}
</div>
);
}
}
export default NotificationStepper;
TabComponent.js
TabContainer.propTypes = {
children: PropTypes.node.isRequired,
dir: PropTypes.string.isRequired,
};
class TabComponent extends Component {
state = {
value: 0,
};
render() {
const {theme} = this.props;
return (
<div className="col-xl-12 col-lg-12 col-md-12 col-12" style={{"margin-top": "15px"}}>
<NotifCard key={0} data={{'name': 'Title of Notification', 'company': 'sayge.ai', 'image': require("assets/images/chrome.png"), 'description': 'Notification Message here'}} styleName="card shadow "/>
</div>
);
}
}
TabComponent.propTypes = {
theme: PropTypes.object.isRequired,
};
export default withStyles(null, {withTheme: true})(TabComponent);
and this is my SendNotification.js
const SendNotification = ({match}) => {
return (
<div className="dashboard animated slideInUpTiny animation-duration-3">
<ContainerHeader match={match} title={<IntlMessages id="sidebar.notification"/>}/>
<div className="row" style={{'flex-wrap': 'no wrap', "flex-direction": 'row'}}>
<div className="col-xl-7 col-lg-7 col-md-7 col-7">
<NotificationStepper/>
<div className='flex-class' style={{'width': '100%'}}>
<Button color="primary" style={{"align-self": "flex-end", "border" : "1px solid", "margin-left": "10px", "margin-bottom": "40px"}} size="small" className="col-md-2 col-2">Fetch</Button>
<Button color="primary" style={{"align-self": "flex-end", "border" : "1px solid", "margin-left": "10px", "margin-bottom": "40px"}} size="small" className="col-md-2 col-2" color="primary">Discard</Button>
</div>
</div>
<div className="col-xl-5 col-lg-5 col-md-5 col-5" style={{"padding-top": "20px"}}>
<span style={{"margin-left" : "20px", "font-weight": "bold"}}>Preview</span>
<TabComponent />
</div>
</div>
</div>
);
};
export default SendNotification;
i need to get the name value from NotificationStepper and Update it in pass it to in TabComponent.
There are plenty of tutorials about that. For instance, this.
import React, { Component, createRef } from "react";
class CustomTextInput extends Component {
textInput = createRef();
focusTextInput = () => this.textInput.current.focus();
render() {
return (
<>
<input type="text" ref={this.textInput} />
<button onClick={this.focusTextInput}>Focus the text input</button>
</>
);
}
}
import React, { useRef } from "react";
const CustomTextInput = () => {
const textInput = useRef();
focusTextInput = () => textInput.current.focus();
return (
<>
<input type="text" ref={textInput} />
<button onClick={focusTextInput}>Focus the text input</button>
</>
);
}

Resources