how should I re-draw table component with entered value - reactjs

I am trying to call an API with given value for drawing data table.
Here is what I want to do and How the actual code works.
How should I fix it? please I need your kind advice.
what I want to do
draw a table with initial value(with 5 rows).
type 2 and click submit button for re-drawing table(with 2 rows)
the table should be given with 2 rows.
How the actual code works
draw a table with initial value(with 5 rows).
type 2 and click submit button for re-drawing table(with 2 rows).
the table is given with 5 rows.
my main code
import React, { useEffect, useState } from 'react';
import Table from 'components/advTable';
import { apiProvider } from 'services/modules/provider';
import {
CBadge,
CDataTable,
CCard,
CCardBody,
CCardHeader,
CCol,
CFormGroup,
CInput,
CLabel,
CSelect,
CRow,
CCardFooter,
CButton,
} from '#coreui/react'
import CIcon from '#coreui/icons-react'
const PendingVertification = () => {
const [query, setQuery] = useState(5);
const [info, setInfo] = useState({});
const [page, setPage] = useState(1);
const [countPerPage, setCountPerPage] = useState(5);
const subURL = "users";
const onChange = (e : any) => {
console.log('the Value: ', e.target.value);
//if I enter number 2 and setQuery(2)
setQuery(e.target.value.toLowerCase());
};
const onSubmit = (e : any) => {
e.preventDefault();
//Call API to draw a table
getTableList();
//setQuery(5);
};
const getTableList = () => {
//Call API for table Data with Given values.
apiProvider.getTabledata(page, query, subURL ).then(res => {
setInfo(res.data);
}).catch(err => {
setInfo({});
});
}
useEffect(() => {
//Call Rest API only once
getTableList();
}, []);
return (
<>
<CRow>
<CCol xs="12" lg="15">
<CCard>
<CCardHeader>
Sample
<small> Form</small>
</CCardHeader>
<CCardBody>
<CRow>
<CCol xs="12">
<CFormGroup>
<CLabel htmlFor="ccnumber">Search Value</CLabel>
<CInput id="ccnumber" placeholder="fill this form" onChange={onChange} required />
</CFormGroup>
</CCol>
</CRow>
</CCardBody>
<CCardFooter>
<CButton type="submit" size="sm" color="primary" onClick={onSubmit}><CIcon name="cil-scrubber"/> Submit</CButton>
<CButton type="reset" size="sm" color="danger"><CIcon name="cil-ban" /> Reset</CButton>
</CCardFooter>
</CCard>
</CCol>
</CRow>
{info && <Table tableData={info} query={query} subURL = {subURL}/>}
</>
//the code above Draws table with given values
);
};
export default PendingVertification;
Table component code
import React, { useEffect, useState, useRef } from 'react';
import DataTable from 'react-data-table-component';
import { apiProvider } from 'services/modules/provider';
interface Props {
tableData: any,
query: number,
subURL: string
}
const Table: React.FunctionComponent<Props> = ({ tableData, query, subURL}) => {
const columns = [
{
name: tableData.mata? tableData.meta.firstColum : 'Avatar',
cell: (row : any) => <img height="30px" width="30px" alt={row.first_name} src={row.avatar} />
},
{
name: tableData.mata? tableData.meta.secondColum : 'First Name',
selector: 'first_name'
},
{
name: tableData.mata? tableData.meta.thirdColum : 'Last Name',
selector: 'last_name'
},
{
name: tableData.mata? tableData.meta.fourthColum : 'e-mail',
selector: 'email'
}
];
//set The value for drawing table
// countPerpage should be 2 when I enter 2 but it always contain number 5.
const [page, setPage] = useState(1);
const [countPerPage, setCountPerPage] = useState(query);
const [users, setUsers] = useState<any>({tableData});
const isMounted = useRef(false);
const getTableList = async () => {
//re-draw table with give values.
const response = await apiProvider.getTabledata(page, countPerPage, subURL);
setUsers(response);
}
useEffect(() => {
if(isMounted.current) {
getTableList();
} else {
isMounted.current = true;
}
}, [page, countPerPage, tableData]);
return (
<>
<DataTable
title="Table (Server side Pagination)"
columns={columns}
data={users.data}
highlightOnHover
pagination
paginationServer
paginationTotalRows={users.total}
paginationPerPage={countPerPage}
paginationRowsPerPageOptions={[5, 10, 15, 25, 50]}
paginationComponentOptions={{
noRowsPerPage: false
}}
onChangeRowsPerPage= { rowsPerPage => setCountPerPage(rowsPerPage)}
onChangePage={page => setPage(page)}
/>
</>
);
};
export default Table;

Try this in Table component:
//New useEffect, keep your other one
useEffect(() => {setCountPerPage(query)}, [query])

Related

Betton are not disappear when removing atomFamily recoil.js

Why when user click "remove button" in ListItem component, the item text are disappear but the button itself are still there, if possible how to get rid of that "remove button" too?
P.S The atom family item are got removed but the ui are not get updated ("remove button" are still there), is that a normal things?
import React, {useState} from "react";
import { atom, useRecoilState, useResetRecoilState, useRecoilCallback, atomFamily, useRecoilValue, useSetRecoilState } from "recoil";
import "./styles.css";
const idsState = atom({
key: "circleColor",
default: [],
});
const noteState = atomFamily({
key: "noteState",
default: []
})
const ListItem = ({ id }) => {
const [note, setNote] = useRecoilState(noteState(id));
const handleRemoveNote = useResetRecoilState(noteState(id));
return (
<div key={note.id} className="list-item">
<p>{note.text}</p>
<button onClick={handleRemoveNote}>Remove</button>
</div>
)
}
const App = () => {
const ids = useRecoilValue(idsState);
const nextId = ids.length;
const addNote = useRecoilCallback(({set}) => (newNote) => {
set(idsState, [...ids, nextId])
set(noteState(nextId), newNote);
})
const [text, setText] = useState("");
const handleAddNote = (e) => {
e.preventDefault();
const id = Math.round(Math.random() * 1000);
const newNote = {
text,
id,
subNote: [
{
label: "zero",
value: "0"
},
{
label: "one",
value: "1"
},
{
label: "two",
value: "two"
}
]
};
addNote(newNote);
}
return (
<div>
<form className="form-container" onSubmit={handleAddNote}>
<input onChange={e => setText(e.target.value)} />
<button>Add</button>
</form>
<div>
{ids.map(id => (
<ListItem id={id} />
))}
</div>
</div>
);
};
export default App;

Options not showing when using custom input in React-Bootstrap-TypeAhead

I am using React-Bootstrap-TypeAhead's latest version in my React project. The main goal is to display the options menu when the user types. The menu is displayed when using the default input component but once I use the render input method for customization the options menu stops showing:
working example
import React, { useState } from 'react';
import { AsyncTypeahead } from 'react-bootstrap-typeahead';
/* example-start */
const BasicExample = ({ key, label }) => {
const [singleSelections, setSingleSelections] = useState([]);
const [multiSelections, setMultiSelections] = useState([]);
const [query, setQuery] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [options, setOptions] = useState([]);
const PER_PAGE = 50;
const SEARCH_URI = 'https://api.github.com/search/users';
function makeAndHandleRequest(query, page = 1) {
return fetch(`${SEARCH_URI}?q=${query}+in:login&page=${page}&per_page=50`)
.then((resp) => resp.json())
.then(({ items, total_count }) => {
/* eslint-disable-line camelcase */
const options = items.map((i) => ({
avatar_url: i.avatar_url,
id: i.id,
login: i.login,
}));
return { options, total_count };
})
.catch((err) => console.log(err));
}
const _handleInputChange = (query) => {
setQuery(query);
};
const _handlePagination = (e, shownResults) => {
const { query } = this.state;
const cachedQuery = this._cache[query];
// Don't make another request if:
// - the cached results exceed the shown results
// - we've already fetched all possible results
if (cachedQuery.options.length > shownResults || cachedQuery.options.length === cachedQuery.total_count) {
return;
}
setIsLoading(true);
const page = cachedQuery.page + 1;
makeAndHandleRequest(query, page).then((resp) => {
const options = cachedQuery.options.concat(resp.options);
// this._cache[query] = { ...cachedQuery, options, page };
setIsLoading(false);
setOptions(options);
});
};
const _handleSearch = (query) => {
setIsLoading(true);
makeAndHandleRequest(query).then((resp) => {
setIsLoading(true);
setOptions(resp?.options || []);
});
};
return (
<>
<AsyncTypeahead
{...{ query, isLoading, options }}
id="async-pagination-example"
labelKey="login"
maxResults={PER_PAGE - 1}
minLength={2}
onInputChange={_handleInputChange}
onPaginate={_handlePagination}
onSearch={_handleSearch}
renderInput={({ inputRef, referenceElementRef, ...inputProps }) => (
<div className="form-group h-64">
<label>Job Category</label>
<div className="input-group">
<input
type="text"
{...inputProps}
ref={(input) => {
inputRef(input);
// referenceElementRef(input);
}}
className="form-control"
placeholder=""
/>
</div>
</div>
)}
paginate
placeholder="Search for a Github user..."
renderMenuItemChildren={(option) => (
<div key={option.id}>
<img
alt={option.login}
src={option.avatar_url}
style={{
height: '24px',
marginRight: '10px',
width: '24px',
}}
/>
<span>{option.login}</span>
</div>
)}
useCache={false}
/>
</>
);
};
/* example-end */
export default BasicExample;
The reason you're not seeing any results rendered is that _handleInputChange is triggering a re-render and resetting the debounced onSearch handler before it can fire.
You can wrap _handleSearch with useCallback to fix that:
const _handleSearch = useCallback((query) => {
setIsLoading(true);
makeAndHandleRequest(query).then((resp) => {
setIsLoading(false);
setOptions(resp?.options || []);
});
}, []);

How to make data persist on refresh React JS?

I have a code where I mount a table with some firebase data but for some reason the values disappear and I been struggling for the next 2 weeks trying to solve this issue I haven't found a solution to this and I have asked twice already and I have try everything so far but it keeps disappearing.
Important Update
I just want to clarify the following apparently I was wrong the issue wasn't because it was a nested collection as someone mentioned in another question. The issue is because my "user" is getting lost in the process when I refresh.
I bring the user from the login to the app like this:
<Estudiantes user={user} />
and then I receive it as a props
function ListadoPedidos({user})
but is getting lost and because is getting lost when I try to use my firebase as:
estudiantesRef = db.collection("usuarios").doc(user.uid).collection("estudiantes")
since the user is "lost" then the uid will be null. Since is null it will never reach the collection and the docs.
I have a simple solution for you. Simply raise the parsing of localStorage up one level, passing the preloadedState into your component as a prop, and then using that to initialize your state variable.
const ListadoEstudiantes = (props) => {
const estData = JSON.parse(window.localStorage.getItem('estudiantes'));
return <Listado preloadedState={estData} {...props} />;
};
Then initialize state with the prop
const initialState = props.preloadedState || [];
const [estudiantesData, setEstudiantesData] = useState(initialState);
And finally, update the useEffect hook to persist state any time it changes.
useEffect(() => {
window.localStorage.setItem('estudiantes', JSON.stringify(estudiantes));
}, [estudiantes]);
Full Code
import React, { useState, useEffect } from 'react';
import { db } from './firebase';
import { useHistory } from 'react-router-dom';
import './ListadoEstudiantes.css';
import {
DataGrid,
GridToolbarContainer,
GridToolbarFilterButton,
GridToolbarDensitySelector,
} from '#mui/x-data-grid';
import { Button, Container } from '#material-ui/core';
import { IconButton } from '#mui/material';
import PersonAddIcon from '#mui/icons-material/PersonAddSharp';
import ShoppingCartSharpIcon from '#mui/icons-material/ShoppingCartSharp';
import DeleteOutlinedIcon from '#mui/icons-material/DeleteOutlined';
import { Box } from '#mui/system';
const ListadoEstudiantes = (props) => {
const estData = JSON.parse(window.localStorage.getItem('estudiantes'));
return <Listado preloadedState={estData} {...props} />;
};
const Listado = ({ user, preloadedState }) => {
const history = useHistory('');
const crearEstudiante = () => {
history.push('/Crear_Estudiante');
};
const initialState = preloadedState || [];
const [estudiantesData, setEstudiantesData] = useState(initialState);
const parseData = {
pathname: '/Crear_Pedidos',
data: estudiantesData,
};
const realizarPedidos = () => {
if (estudiantesData == 0) {
window.alert('Seleccione al menos un estudiante');
} else {
history.push(parseData);
}
};
function CustomToolbar() {
return (
<GridToolbarContainer>
<GridToolbarFilterButton />
<GridToolbarDensitySelector />
</GridToolbarContainer>
);
}
const [estudiantes, setEstudiantes] = useState([]);
const [selectionModel, setSelectionModel] = useState([]);
const columns = [
{ field: 'id', headerName: 'ID', width: 100 },
{ field: 'nombre', headerName: 'Nombre', width: 200 },
{ field: 'colegio', headerName: 'Colegio', width: 250 },
{ field: 'grado', headerName: 'Grado', width: 150 },
{
field: 'delete',
width: 75,
sortable: false,
disableColumnMenu: true,
renderHeader: () => {
return (
<IconButton
onClick={() => {
const selectedIDs = new Set(selectionModel);
estudiantes
.filter((x) => selectedIDs.has(x.id))
.map((x) => {
db.collection('usuarios')
.doc(user.uid)
.collection('estudiantes')
.doc(x.uid)
.delete();
});
}}
>
<DeleteOutlinedIcon />
</IconButton>
);
},
},
];
const deleteProduct = (estudiante) => {
if (window.confirm('Quiere borrar este estudiante ?')) {
db.collection('usuarios').doc(user.uid).collection('estudiantes').doc(estudiante).delete();
}
};
useEffect(() => {}, [estudiantesData]);
const estudiantesRef = db.collection('usuarios').doc(user.uid).collection('estudiantes');
useEffect(() => {
estudiantesRef.onSnapshot((snapshot) => {
const tempData = [];
snapshot.forEach((doc) => {
const data = doc.data();
tempData.push(data);
});
setEstudiantes(tempData);
console.log(estudiantes);
});
}, []);
useEffect(() => {
window.localStorage.setItem('estudiantes', JSON.stringify(estudiantes));
}, [estudiantes]);
return (
<Container fixed>
<Box mb={5} pt={2} sx={{ textAlign: 'center' }}>
<Button
startIcon={<PersonAddIcon />}
variant="contained"
color="primary"
size="medium"
onClick={crearEstudiante}
>
Crear Estudiantes
</Button>
<Box pl={25} pt={2} mb={2} sx={{ height: '390px', width: '850px', textAlign: 'center' }}>
<DataGrid
rows={estudiantes}
columns={columns}
pageSize={5}
rowsPerPageOptions={[5]}
components={{
Toolbar: CustomToolbar,
}}
checkboxSelection
//Store Data from the row in another variable
onSelectionModelChange={(id) => {
setSelectionModel(id);
const selectedIDs = new Set(id);
const selectedRowData = estudiantes.filter((row) => selectedIDs.has(row.id));
setEstudiantesData(selectedRowData);
}}
{...estudiantes}
/>
</Box>
<Button
startIcon={<ShoppingCartSharpIcon />}
variant="contained"
color="primary"
size="medium"
onClick={realizarPedidos}
>
Crear pedido
</Button>
</Box>
</Container>
);
};
I suspect that it's because this useEffect does not have a dependency array and is bring run on every render.
useEffect (() => {
window.localStorage.setItem("estudiantes", JSON.stringify(estudiantes))
})
Try adding a dependency array as follows:
useEffect (() => {
if (estudiantes && estudiantes.length>0)
window.localStorage.setItem("estudiantes", JSON.stringify(estudiantes))
},[estudiantes])
This will still set the localStorage to [] when it runs on the first render. But when the data is fetched and estudiantes is set, the localStorage value will be updated. So I've added a check to check if it's not the empty array.
Change the dependency array of this useEffect to []:
estudiantesRef.onSnapshot(snapshot => {
const tempData = [];
snapshot.forEach((doc) => {
const data = doc.data();
tempData.push(data);
});
setEstudiantes(tempData);
console.log(estudiantes)
})
}, []);
The data flow in your code is somewhat contradictory, so I modify your code, and it works fine.
You can also try delete or add button, it will modify firebase collection, then update local data.
You can click refresh button in codesandbox previewer (not browser) to observe the status of data update.
Here is the code fargment :
// Set value of `localStorage` to component state if it exist.
useEffect(() => {
const localStorageEstData = window.localStorage.getItem("estudiantes");
localStorageEstData && setEstudiantes(JSON.parse(localStorageEstData));
}, []);
// Sync remote data from firebase to local component data state.
useEffect(() => {
// Subscribe onSnapshot
const unSubscribe = onSnapshot(
collection(db, "usuarios", user.id, "estudiantes"),
(snapshot) => {
const remoteDataSource = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data()
}));
console.info(remoteDataSource);
setEstudiantes(remoteDataSource);
}
);
return () => {
//unSubscribe when component unmount.
unSubscribe();
};
}, [user.id]);
// when `estudiantes` state update, `localStorage` will update too.
useEffect(() => {
window.localStorage.setItem("estudiantes", JSON.stringify(estudiantes));
}, [estudiantes]);
Here is the full code sample :
Hope to help you :)

Radio buttons not toggling, checked or highlighted

import React, { useState, useEffect, Fragment } from "react";
import Button from "../../../Resources/Forms/Button";
import Switch from "../../../Resources/Forms/Switch";
import { POST } from "../../../Utils/api";
import Radio from "../../../Resources/Forms/Radio";
import withAppData from "../../../HOC/withAppData";
const InventorySettings = (props) => {
const [state, setState] = useState({});
const [isSaving, setIsSaving] = useState();
const [isStockRequestChecked, setIsStockRequestChecked] = useState(false);
const getStatus = id => {
return props.context.isSettingsActivated(id) ? 1 : 0;
};
const setBusinessSettings = async () => {
const defaultSettings = [
{ state: "enableStockRequest", id: 53 },
{ state: "connectWarehousePickStock", id: 52 },
{ state: "approveRequestOtp", id: 51 },
{ state: "approveRequestManually", id: 50 }
];
for (const setting of defaultSettings) {
await setState({ [setting.state]: getStatus(setting.id) });
}
};
function chooseApprovalMethod(methodType) {
const currentValue = state[methodType];
setState({[methodType]
: currentValue === 1 ? 0: 1})
}
async function saveApprovalMethod() {
setIsSaving(true)
const approvalSettings = [{text:"approvalRequestManually", id: 51}, {text:"approveRequestOtp", id: 50}]
for(const el of approvalSettings) {
const currentValue = state[el.text];
const data = {
settingId: el.id,
status: currentValue
}
await POST(`Common/AddBusinessSetting`, data);
}
setIsSaving(false);
props.context.getBusinessSettings();
}
const updateBasicSettings = async (id, key) => {
setState({ [key]: !state[key] ? 1 : 0 });
const data = {
SettingId: id,
Status: state[key],
};
await POST(`Common/AddBusinessSetting`, data);
props.context.getBusinessSettings();
};
useEffect(() => {
setBusinessSettings();
}, []);
return (
<Fragment>
<div className="basic-settings-section">
<Switch
label={"Connect Warehouse Stock to pick stock"}
light={true}
checked={state && state.connectWarehousePickStock === 1}
onChange={() => updateBasicSettings(52, "connectWarehousePickStock")}
></Switch>
</div>
<div className="basic-settings-section">
<Switch
label={"Stock Request"}
light={true}
checked={isStockRequestChecked}
onChange={() => setIsStockRequestChecked(!isStockRequestChecked)}
></Switch>
{isStockRequestChecked && (
<div className="basic-settings-plan-generate">
<div
className="form__label"
style={{ padding: "2px", marginBottom: "20px" }}
>
<p>Please choose an approval method</p>
</div>
<Radio
label={"Manual Approval"}
name="approval"
value="50"
id="50"
checked={state && state.approveRequestManually === 1}
// onChange={() => (chooseApprovalMethod)}
/>
<Radio
label={"OTP Approval"}
name="approval"
value="51"
id="51"
checked={state && state.approveRequestOtp === 1}
// onChange={() => (chooseApprovalMethod)}
/>
<div className="password-settings-btn"
// onClick={props.context.showToast}
>
<Button
type={"outline"}
size={"medium"}
text={"Save"}
disabled={!state.approveRequestOtp && !state.approveRequestManually}
withMargin={false}
loading={isSaving}
onClick={saveApprovalMethod}
></Button>
</div>
</div>
)}
</div>
</Fragment>
);
}
export default withAppData(InventorySettings);
I added the chooseApprovalMethod function to the radio buttons but still I wasn't getting it well. So I had to call there state using state.text is equal to 1. Please help me out I don't think I know what I'm doing anymore.
Please above are my code, the radio buttons aren't checking or highlighting, so I want them to be checked when clicked on, and I want there ids to be saved when clicking on the save button.
So please guys help me out, as I don't understand it anymore.

React calls api thousands of times inside a useEffect

I am building a ToDoList with React and a Django rest Api but I am also using a Datepicker to render all the tasks for the day by the date created. But every time the site loads the api is called thousands of times. The goal would be to only render the tasks for the specific day when the date is changed or a new task for the day is added and not call the backend constalnly the problem seams to lay at the ToDoList because evertwhere else the props.date is only called once and not in a loop.
import React, { useState } from 'react'
import 'date-fns'
import Grid from '#material-ui/core/Grid'
import DateFnsUtils from '#date-io/date-fns'
import{
MuiPickersUtilsProvider,
KeyboardTimePicker,
KeyboardDatePicker
} from '#material-ui/pickers'
import TodoForm from '../ToDo/TodoForm'
function Datepicker() {
const initialDate = new Date(Date.now())
const [selectDate, setSelectDate] = useState(
`${initialDate.getFullYear()}-${initialDate.getMonth()+1}-${initialDate.getDate()}`
)
const handleDateChange = (date) =>{
setSelectDate(`${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}`)
}
return (
<div>
<div>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Grid container justify='space-around'>
<KeyboardDatePicker
disableToolbar
varient='inline'
format='MM/dd/yy'
margin='normal'
id='date-picker'
label='Pick your Date'
value={selectDate}
onChange={handleDateChange}
KeyboradButtonProps={{
'aris-label': 'change date'
}}
/>
</Grid>
</MuiPickersUtilsProvider>
</div>
<div>
<TodoForm date={selectDate}/>
</div>
</div>
)
}
export default Datepicker
import React, { Component, useState,useEffect } from 'react'
import Select from 'react-select'
import { apiTaskCreate } from './lookup'
import { ActionBtn } from './buttons'
import TodoList from './TodoList'
function TodoForm(props) {
const [newTasks, setNewTasks] = useState([])
const [taskname, SetTaskname] = useState('')
const [Importants, setImportants] = useState({})
const [TimeComplete, setTimeComplete] = useState({})
const handleChange = e => {
SetTaskname(e.target.value)
}
function onChangeImportants(value){
setImportants(value.value)
}
function onChangeTimeComplete(value){
setTimeComplete(value.value)
}
const handleSubmit = e =>{
e.preventDefault()
SetTaskname('')
let tempNewTasks = [...newTasks]
apiTaskCreate(taskname,Importants,TimeComplete,(response, status)=>{
// console.log(response, status)
if (status === 201){
tempNewTasks.unshift(response)
setNewTasks(tempNewTasks)
} else {
console.log(response)
alert("an error accourd")
}
})
}
const Importants_options = [
{ value: '1', label: 1 },
{ value: '2', label: 2 },
{ value: '3', label: 3 },
{ value: '4', label: 4 },
{ value: '5', label: 5 },
]
const Time_options = [
{ value: '1', label: 30 },
{ value: '2', label: 60 },
{ value: '3', label: 90 },
{ value: '4', label: 120 },
{ value: '5', label: 150 },
{ value: '6', label: 180 },
]
return (
<div className={props.className}>
<div className='col-11 mb-3'>
<form className='todo-form mb-3' onSubmit={handleSubmit}>
<input type='text' value={taskname} placeholder='Task Name'
name='task_name' className='todo-input' onChange={handleChange}></input>
<Select onChange={onChangeImportants} options={Importants_options} placeholder="Importants Score"/>
<Select onChange={onChangeTimeComplete} options={Time_options} placeholder="Time to complete"/>
<button className='btn btn-primary'>Submit</button>
<ActionBtn action={{type: 'optimize', display:"Optimize"}}/>
</form>
</div>
<div className='container'>
<TodoList newTasks={newTasks} {...props}/>
</div>
</div>
)
}
export default TodoForm
import React, {useState, useEffect} from 'react'
import { apiTaskList } from './lookup'
import Task from './Task'
function TodoList(props) {
const [tasksInit, setTasksInit] = useState([])
const [tasks, setTasks] = useState([])
const [tasksDidSet, setTasksDidSet] = useState(false)
const initialDate = new Date(Date.now())
const [date, setDate] = useState("2021-04-12")
// `${initialDate.getFullYear()}-${initialDate.getMonth()+1}-${initialDate.getDate()}`
useEffect( () =>{
const final = [...props.newTasks].concat(tasksInit)
if (final.length !== tasks.length) {
setTasks(final)
}
}, [props.newTasks, tasks, tasksInit])
useEffect(() => {
if (tasksDidSet === false) {
const handleTasksListLookup = (response, status) => {
if (status === 200) {
setTasksInit(response)
setDate(props.date)
console.log(date)
}
}
apiTaskList("admin", date ,handleTasksListLookup)
}
}, [tasksInit, setTasksDidSet, setTasksDidSet, date])
return tasks.map((item, index)=>{
return <Task task={item} className='d-flex p-2 justify-content-between border bg-white text-dark' key={`${index}-${item.id}`}/>
})
}
export default TodoList;
import { backendlookup } from "../lookup/lookup";
export function apiTaskCreate(newTask_Name,newImportans_Score,newTime_to_complete,callback) {
backendlookup('POST', 'create',callback, {
Task_name: newTask_Name,
Importants_Score: newImportans_Score,
Time_to_Finish: newTime_to_complete,
})
}
export function apiTaskList(username,date,callback) {
let endpoint = 'tasks'
if (date){
endpoint = `tasks?username=${username}&date=${date}`
}
backendlookup('GET', endpoint ,callback)
}
export function apiPartyActionOptimize(action,callback) {
backendlookup('POST', 'action-optimize',callback, {action:action})
You are adding a dependency to useEffect which itself is being updated inside it. If you do so, your useEffect execution will go into an infinite loop.
You can make use of functional version of setState to update the tasks state.
Your updated code will look as follows
useEffect( () =>{
const final = [...props.newTasks].concat(tasksInit);
setTasks(tasks => {
if (final.length !== tasks.length) {
return final;
}
return tasks
});
}, [props.newTasks, tasksInit])
useEffect(() => {
if (tasksDidSet === false) {
const handleTasksListLookup = (response, status) => {
if (status === 200) {
setTasksInit(response);
setDate(props.date);
}
}
apiTaskList("admin", date ,handleTasksListLookup)
}
}, [setTasksInit, props.date, tasksDidSet])
When you call the setTasks method inside the useEffect function it updates the tasks value and because you have the tasks variable as one of the dependencies in the useEffect callback, the API gets called indefinitely. Remove tasks from the useEffect dependency and it should work.

Resources