React state.map return empty array - javascript

I created an application using the covid19 api. I store state and function in the context api. I want to create an apexchart, but the dailydata map that keeps it in the same place returns an empty array. I need to enter my options data with dailyDate
const {country} = useContext(countryContext);
const [dailyData,setDailyData] = useState([]);
useEffect(() => {
const fetchdata = async () => {
const data = await dayOneAllStatus(country);
setDailyData(data);
};
fetchdata();
},[country])
const [options,setOptions] = useState({
chart: {
height: 350,
type: 'area'
},
dataLabels: {
enabled: false
},
stroke: {
curve: 'smooth'
},
xaxis: {
type: 'datetime',
categories: dailyData.map(item => item.Date)
},
tooltip: {
x: {
format: 'dd/MM/yy'
},
},
});
const [series,setSeries] = useState([
{
name: 'Vaka',
data: dailyData.map(item => item.Confirmed)
}, {
name: 'İyileşen',
data: dailyData.map(item => item.Recovered)
},
{
name: 'Ölüm',
data: dailyData.map(item => item.Deaths)
}
]);
return (
<div id="chart">
<Chart options={options} series={series} type="area" height={350} />
</div>
)
dailyData console.log example
Array(426) [ {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, … ]
[0…99]
[100…199]
[200…299]​
[300…399]
[400…425]
length: 426

When you call useState, the parameter that's passed in is the initial-value. So when the function re-runs because dailyData has updated, the values in options and series don't update.
If you're not actually using setSeries and setOptions anywhere, you're better off leaving them as normal variables that are computed using dailyData:
const {country} = useContext(countryContext);
const [dailyData,setDailyData] = useState([]);
useEffect(() => {
const fetchdata = async () => {
const data = await dayOneAllStatus(country);
setDailyData(data);
};
fetchdata();
},[country])
const options = {
chart: {
height: 350,
type: 'area'
},
dataLabels: {
enabled: false
},
stroke: {
curve: 'smooth'
},
xaxis: {
type: 'datetime',
categories: dailyData.map(item => item.Date)
},
tooltip: {
x: {
format: 'dd/MM/yy'
},
},
};
const series = [
{
name: 'Vaka',
data: dailyData.map(item => item.Confirmed)
}, {
name: 'İyileşen',
data: dailyData.map(item => item.Recovered)
},
{
name: 'Ölüm',
data: dailyData.map(item => item.Deaths)
}
];
return (
<div id="chart">
<Chart options={options} series={series} type="area" height={350} />
</div>
)

Related

Using React, Ts, AntV g2: Form updates re-render the chart, but seem to layer updated version over the previous one

I am using React to create an editable chart (via form input to enter chart settings, and then update the chartsettings object state with new values from the form). I have noticed that the visual of the chart does update, but with an overlay of the previous chart appearance remaining. What am I doing wrong?
Here is how the COMPONENTS are working together & then their code:
SCATTERPAGE consumes SCATTERCHART & CHARTSETTINGS;
CHARTSETTINGS consumes various INPUTCOMPONENTs. The input components trigger updates in the the state of the SCATTERPAGE, after their own state is updated
SCATTERCHART is simply passed the settings object state
Settings object state & functions to set it, are passed down via props from the SCATTERPAGE, via the CHARTSETTINGS into the INPUTCOMPONENTs
SCATTERPAGE's code:
import React, { useEffect, useState } from 'react'
import { ScatterChart } from '#components/charts/area-2-0'
import {
Grid,
Box,
Button,
Paper,
Stack,
Title,
createStyles,
Center
} from '#mantine/core'
import { PlayerPlay } from 'tabler-icons-react'
import { ChartSettings } from '#/components/ChartSettings'
import { modelChartSettingsObject } from './modelChartSettingsObject'
const useStyles = createStyles((theme) => ({
ChartContainer: {
width: '100%',
height: '500px',
borderRadius: '15px',
background: '#000000',
p: 2
}
}))
const settingsConfig = [
{
title: 'data',
elements: [
{
title: 'dataset',
typeConfig: {
label: 'Dataset to show in Chart',
placeholder: 'insert your dataset'
},
type: 'data'
}
]
},
{
title: 'axis',
elements: [
{
title: 'xExplanatoryVariable',
type: 'select',
typeConfig: {
label: 'make a selection',
placeholder: 'selections',
data: [
{ value: 'durationDays', label: 'durationDays' },
{ value: 'sizeSqm', label: 'sizeSqm' }
]
}
},
{
title: 'grid',
elements: [
{
title: 'x',
type: 'switcher',
typeConfig: {
label: 'show grid for x axis'
}
},
{
title: 'y',
type: 'switcher',
typeConfig: {
label: 'show grid for y axis'
}
},
{
title: 'stroke',
type: 'color',
typeConfig: {
placeholder: 'pick stroke color',
label: 'pick stroke color'
}
},
{
title: 'lineWidth',
type: 'number',
typeConfig: {
label: 'lineWidth',
min: 0,
max: 100
}
}
]
},
{
title: 'label',
elements: [
{
title: 'fontSize',
type: 'number',
typeConfig: {
label: 'fontSize'
}
},
{
title: 'color',
type: 'color',
typeConfig: {
label: 'label color'
}
}
]
},
{
title: 'tickLineWidth',
type: 'number',
typeConfig: {
label: 'tickLineWidth'
}
},
{
title: 'tickLineLength',
type: 'number',
typeConfig: {
label: 'tickLineLength'
}
},
{
title: 'lineWidth',
type: 'number',
typeConfig: {
label: 'linewidth'
}
},
{
title: 'subTickLineLength',
type: 'number',
typeConfig: {
label: 'subTickLineLength'
}
},
{
title: 'subTickLineLength',
type: 'number',
typeConfig: {
label: 'subTickLineLength'
}
},
{
title: 'subTickLineCount',
type: 'number',
typeConfig: {
label: 'subTickLineCount'
}
},
{
title: 'color',
type: 'color',
typeConfig: {
label: 'color'
}
}
]
},
{
title: 'regressionLine',
elements: [
{
title: 'color',
type: 'color'
},
{
title: 'lineWidth',
type: 'number'
}
]
},
{
title: 'points',
elements: [
{
title: 'number of rooms',
type: 'select',
typeConfig: {
label: 'dots highighted are representative of X rooms:',
placeholder: 'selections',
data: [
{ value: 1, label: '1' },
{ value: 2, label: '2' },
{ value: 3, label: '3' },
{ value: 4, label: '4' }
]
}
},
{
title: 'color',
type: 'color'
},
{
title: 'fillOpacity',
type: 'slider'
},
{
title: 'radius',
type: 'number'
}
]
},
{
title: 'area',
elements: [
{
title: 'color',
type: 'color'
}
]
}
]
type downloadHandlerType = (svg: string) => void
export const Scatter = () => {
const { classes } = useStyles()
const [downloadingState, setDownloadingState] = useState(false)
const downloadSVGHandler: downloadHandlerType = (svg: string) => {
const preface = '<?xml version="1.0" standalone="no"?>\r\n'
const svgBlob = new Blob([preface, svg], {
type: 'image/svg+xml;charset=utf-8'
})
const svgUrl = URL.createObjectURL(svgBlob)
const downloadLink = document.createElement('a')
downloadLink.href = svgUrl
downloadLink.download = 'chart.svg'
document.body.appendChild(downloadLink)
downloadLink.click()
document.body.removeChild(downloadLink)
downloadFinishHandler()
}
const downloadFinishHandler = () => {
setDownloadingState(false)
}
const startDownloadHandler = () => {
setDownloadingState(true)
}
const setX = (a: any) => {
let x: any
a === 'durationDays' ? (x = 'x') : (x = 'x1')
return x
}
const [chartSettingsDirect, setChartSettingsDirect] = useState(
modelChartSettingsObject
)
const applySettings = () => {
let cloneBeforeSet: any = { ...chartSettingsDirect }
cloneBeforeSet.rerender = !cloneBeforeSet.rerender
setChartSettingsDirect(cloneBeforeSet)
}
useEffect(() => {
console.log('chart settings set directly: ', chartSettingsDirect)
}, [chartSettingsDirect])
return (
<Stack>
<Grid gutter={40}>
<Grid.Col span={12}>
<Paper shadow='xs' radius='md' p='xl'>
<Title order={1}>Area 2.0 - Scatter</Title>
<Box
sx={{
display: 'flex',
justifyContent: 'flex-end',
gap: '1rem'
}}
>
<Button
leftIcon={<PlayerPlay size={14} />}
onClick={() => {
applySettings()
}}
>
render chart(s)
</Button>
<Button
onClick={() => {
startDownloadHandler()
}}
>
Download SVG
</Button>
</Box>
<ChartSettings
// loadChartSettingsUp={setState}
setChartSettingsDirect={setChartSettingsDirect}
chartSettingsDirect={chartSettingsDirect}
settingsConfigMain={settingsConfig}
/>
</Paper>
</Grid.Col>
<Grid.Col span={12}>
<Paper
className={classes.ChartContainer}
shadow='xs'
radius='md'
p='xl'
>
<Center sx={{ height: '100%' }}>
<Box sx={{ width: '864px', height: '446px' }}>
<ScatterChart
settings={chartSettingsDirect}
// settings={state}
downloadingState={downloadingState}
handleDownload={downloadSVGHandler}
// x='x1'
x={setX(modelChartSettingsObject.axis.xExplanatoryVariable)}
y='y' //priceEur
/>
</Box>
</Center>
</Paper>
</Grid.Col>
</Grid>
</Stack>
)
}
CHARTSETTINGS' code:
import React, { FC } from 'react'
import { Accordion, Title, Grid, Tabs, Box } from '#mantine/core'
import {
ColorRenderer,
DataRenderer,
NumberInputRenderer,
SliderRenderer,
SwitcherRenderer,
SelectRenderer
} from './renderer'
import { useChartSettings } from '#/context/chartSettingsContext'
const mappingObject: any = {
color: ColorRenderer,
data: DataRenderer,
number: NumberInputRenderer,
slider: SliderRenderer,
switcher: SwitcherRenderer,
select: SelectRenderer
}
const SettingsComponent = ({
settingsConfig,
firstLevel,
parent,
setChartSettingsDirect,
chartSettingsDirect
}: any) => {
const hasChildren = settingsConfig?.elements?.length
const { type, title, typeConfig } = settingsConfig
const SettingsItem = type ? mappingObject[type] : null
return (
<>
{type && (
<SettingsItem
title={title}
typeConfig={typeConfig}
parent={parent}
setChartSettingsDirect={setChartSettingsDirect}
chartSettingsDirect={chartSettingsDirect}
/>
)}
<Box sx={{ padding: 2 }}>
{hasChildren &&
(firstLevel && settingsConfig.elements.length > 1 ? (
<Accordion>
{settingsConfig.elements.map((configItem: any) => (
<Accordion.Item label={configItem.title}>
<SettingsComponent
settingsConfig={configItem}
parent={parent}
setChartSettingsDirect={setChartSettingsDirect}
chartSettingsDirect={chartSettingsDirect}
/>
</Accordion.Item>
))}
</Accordion>
) : (
<Grid>
{settingsConfig.elements.map((configItem: any) => (
<Grid.Col span={settingsConfig.elements.length > 1 ? 6 : 12}>
{firstLevel && <Title order={6}>{configItem.title}</Title>}
<SettingsComponent
setChartSettingsDirect={setChartSettingsDirect}
chartSettingsDirect={chartSettingsDirect}
settingsConfig={configItem}
parent={parent}
/>
</Grid.Col>
))}
</Grid>
))}
</Box>
</>
)
}
export const ChartSettings: FC<any> = ({
settingsConfigMain,
setChartSettingsDirect,
chartSettingsDirect
}) => {
const chartSettings = useChartSettings()
return (
<Box>
<Tabs>
{settingsConfigMain.map((configItem: any) => (
<Tabs.Tab label={configItem.title}>
<SettingsComponent
settingsConfig={configItem}
firstLevel
parent={configItem.title}
setChartSettingsDirect={setChartSettingsDirect}
chartSettingsDirect={chartSettingsDirect}
/>
</Tabs.Tab>
))}
</Tabs>
</Box>
)
}
SAMPLE INPUT COMPONENT's code:
(SELECT)
import React, { FC, useEffect, useState } from 'react'
import { Select, Box } from '#mantine/core'
export const SelectRenderer: FC<any> = ({
title,
parent,
typeConfig,
setChartSettingsDirect,
chartSettingsDirect
}) => {
const [selection, setSelection] = useState('durationDays')
useEffect(() => {
let cloneBeforeSet: any = { ...chartSettingsDirect }
cloneBeforeSet[parent][title] = selection
setChartSettingsDirect(cloneBeforeSet)
}, [selection])
return (
<Box>
<Select value={selection} {...typeConfig} onChange={setSelection} />
</Box>
)
}

useEffect not printing div element react hooks

I have this Chart component. useEffect works as componentDidMount() so it should first render the DOM and then should call the fetchChartData. But the issue I am facing here is I get null in console.log("111111111", document.getElementById("data-consumed")) at first and after that I get the DOM elements and resulting I get error from the Highcharts
Uncaught (in promise) Error: Highcharts error #13
So I need to know why this is happening as useEffect works as componentDidMount and should render the DOM first.
const Chart2 = (props) => {
const fetchChartData = async () => {
const { fetchChartData } = props;
const startDate = moment().startOf("year").toISOString();
const endDate = moment().endOf("year").toISOString();
const data = await fetchChartData({ startDate, endDate, userId: "XXXXXXX" });
console.log("111111111", document.getElementById("data-consumed"))
Highcharts.chart("data-consumed", {
chart: {
type: "column",
},
title: {
text: null,
},
subtitle: {
text: "Source: WorldClimate.com",
},
xAxis: {
categories: data.map(({ _id }) => _id),
crosshair: true,
},
yAxis: {
min: 0,
title: {
text: "Rainfall (mm)",
},
},
plotOptions: {
column: {
pointPadding: -0.1,
borderWidth: 0,
color: "#5036D6",
},
},
series: [
{
name: null,
data: data.map(({ processingStorage }) => processingStorage),
},
],
});
};
useEffect(() => {
fetchChartData();
}, []);
return (
<div className="chart-container cursor-pointer">
<div className="chart-block">
<h4>Data Consumed</h4>
<div id="data-consumed" className="graph-block" />
</div>
</div>
);
};
export default Chart2;
Try using a setTimeout function. Call the fetchChartData function inside setTimeout
useEffect(() => {
setTimeout(()=> {
fetchChartData();
}, 2000)
}, []);

How to Render Chart Datasets in Vue?

I am currently making a reports page and currently struggling how to render the dataset to my BarChart. I have no problems showing static data to the chart but when I use axios it does not work. I read solutions about using watchers and mounted. But I am confused how to apply it if my BarChart is in another component.
This is my BarChart Code:
import { Bar } from "vue-chartjs";
export default {
name: "BarChart",
extends: Bar,
data() {
return {};
},
props: {
label: {
type: Array,
},
chartData: {
type: Array,
},
options: {
type: Object,
},
},
mounted() {
const dates = this.chartData.map((d) => d.date);
const totalCheckIn = this.chartData.map((d) => d.totalCheckIn);
const totalCheckOut = this.chartData.map((d) => d.totalCheckout);
this.renderChart(
{
labels: dates,
datasets: [
{
label: this.label[0],
data: totalCheckIn,
},
{
label: this.label[1],
data: totalCheckOut,
},
],
},
this.options
);
},
};
In my reports component this is how I used it:
<BarChart
v-bind:chartData="checkIn"
v-bind:options="checkInOptions"
v-bind:label="checkInLabel"
></BarChart>
import BarChart from "../components/BarChart";
export default {
name: "Reports",
components: { BarChart },
data() {
return {
checkInOptions: {
responsive: true,
maintainAspectRatio: false,
},
checkIn: [
{ date: "1", totalCheckIn: "2", totalCheckout: "2" },
{ date: "2", totalCheckIn: "1", totalCheckout: "2" },
],
checkInLabel: ["Check In", "CheckOut"],
}
},
beforeMount() {
axios
.get('http://localhost:3000/monthly-checkin/'+this.month+'/'+this.year+'')
.then((res) => {
this.checkIn = res.data.monthly;
console.log(this.checkIn)
})
.catch((err) => {
console.log(err.response.data.message);
});
}
}
Please help
Use watch inside your BarChart component as below:
watch:{
chartData:function(newVal,OldVal){
//assign chart data
},
},
Afterwards you need to execute the method where your bar chart data could be updated. Below will be the full snippet.
import { Bar } from "vue-chartjs";
export default {
name: "BarChart",
extends: Bar,
data() {
return {};
},
props: {
label: {
type: Array,
},
chartData: {
type: Array,
},
options: {
type: Object,
},
},
watch: {
chartData: function (newVal, OldVal) {
this.updateChart()
},
},
mounted() {
this.updateChart()
},
methods: {
updateChart() {
const dates = this.chartData.map((d) => d.date);
const totalCheckIn = this.chartData.map((d) => d.totalCheckIn);
const totalCheckOut = this.chartData.map((d) => d.totalCheckout);
this.renderChart(
{
labels: dates,
datasets: [
{
label: this.label[0],
data: totalCheckIn,
},
{
label: this.label[1],
data: totalCheckOut,
},
],
},
this.options
);
}
}
};

React.js: Add action icons (edit, delete) in table using material-ui

I have an existing table wherein I used a library called react-bootstrap-table-next
It serves its purpose of showing data in a table in which the values are from a JSON response
However, I want to add an Action column containing edit and delete
I want to achieve this using material-ui icons
Any advice as to how should I start? Should I fully convert my table first into material-ui to achieve this?
OR I can just edit profiles state array and map it into a new array containing icons?
ProfileMaintenance.js
const [profiles, setProfiles] = useState([]); // populate table with saved profiles
const retrieveProfiles = useCallback(() => {
ProfileMaintenanceService.retrieveProfiles()
.then((response) => {
console.log(
"ProfileMaintenance - retrieveProfiles response.data >>> ",
response.data
);
setProfiles(response.data);
})
.catch((error) => {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers); // send to logger
if (
error.response.data.error !== undefined &&
error.response.data.error != ""
) {
store.addNotification({
...notification,
type: "danger",
message: error.response.data.error,
dismiss: {
duration: 5000,
},
});
} else {
store.addNotification({
...notification,
type: "danger",
message:
"Server responded with a status code that falls out of the range of 2xx",
dismiss: {
duration: 5000,
},
});
}
} else if (error.request) {
// if API is down
console.log(error.request); // send to logger
store.addNotification({
...notification,
type: "danger",
message: "Request was made but no response was received",
dismiss: {
duration: 5000,
},
});
}
});
});
const columnsProfile = [
// {
// headerStyle: {
// backgroundColor: '#b3b3b3'
// },
// dataField: 'id', // for dev only
// text: 'ID',
// sort: true
// },
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "profileName",
text: "Name",
sort: true,
filter: textFilter(),
},
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "createdBy",
text: "Creator",
sort: true,
},
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "creationDate",
text: "Creation Date",
sort: true,
// filter: dateFilter()
},
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "lastModifier",
text: "Last Modifier",
sort: true,
},
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "lastModification",
text: "Last Modification",
sort: true,
},
{
headerStyle: {
backgroundColor: "#b3b3b3",
},
dataField: "action",
text: "Action",
},
];
const options = {
paginationSize: 4,
pageStartIndex: 1,
alwaysShowAllBtns: true,
hideSizePerPage: true,
firstPageText: "First",
prePageText: "Back",
nextPageText: "Next",
lastPageText: "Last",
nextPageTitle: "First page",
prePageTitle: "Pre page",
firstPageTitle: "Next page",
lastPageTitle: "Last page",
showTotal: true,
paginationTotalRenderer: customTotal,
sizePerPageList: [
{
text: "5",
value: 5,
},
{
text: "10",
value: 10,
},
{
text: "All",
value: profiles.length,
},
],
};
return (
<BootstrapTable
keyField="id"
hover
data={profiles}
columns={columnsProfile}
defaultSorted={defaultSorted}
filter={filterFactory()}
selectRow={selectRowClient}
noDataIndication="No record(s) found."
pagination={paginationFactory(options)}
/>
)
As you want material icon, I suggest to use material ui table. Please below example to edit or delete row from material ui table.
import React from 'react';
import MaterialTable from 'material-table';
export default function MaterialTableDemo() {
const [state, setState] = React.useState({
columns: [
{ title: 'Name', field: 'name' },
{ title: 'Surname', field: 'surname' },
{ title: 'Birth Year', field: 'birthYear', type: 'numeric' },
{
title: 'Birth Place',
field: 'birthCity',
lookup: { 34: 'İstanbul', 63: 'Şanlıurfa' },
},
],
data: [
{ name: 'Mehmet', surname: 'Baran', birthYear: 1987, birthCity: 63 },
{
name: 'Zerya Betül',
surname: 'Baran',
birthYear: 2017,
birthCity: 34,
},
],
});
return (
<MaterialTable
title="Editable Example"
columns={state.columns}
data={state.data}
editable={{
onRowAdd: (newData) =>
new Promise((resolve) => {
setTimeout(() => {
resolve();
setState((prevState) => {
const data = [...prevState.data];
data.push(newData);
return { ...prevState, data };
});
}, 600);
}),
onRowUpdate: (newData, oldData) =>
new Promise((resolve) => {
setTimeout(() => {
resolve();
if (oldData) {
setState((prevState) => {
const data = [...prevState.data];
data[data.indexOf(oldData)] = newData;
return { ...prevState, data };
});
}
}, 600);
}),
onRowDelete: (oldData) =>
new Promise((resolve) => {
setTimeout(() => {
resolve();
setState((prevState) => {
const data = [...prevState.data];
data.splice(data.indexOf(oldData), 1);
return { ...prevState, data };
});
}, 600);
}),
}}
/>
);
}

How to render a material-table using a JSON that comes from a API response?

I'm new on ReactJS and this is my first page that I created, but I'm having some problems with set variables.
What I need is fill the variable table.data with the values that comes from const response = await api.get('/users') and render the table with this values when page loads.
I have the following code:
import React, { useState, useEffect } from 'react';
import { Fade } from "#material-ui/core";
import MaterialTable from 'material-table';
import { makeStyles } from '#material-ui/core/styles';
import api from '../../services/api.js';
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
width: '70%',
margin: 'auto',
marginTop: 20,
boxShadow: '0px 0px 8px 0px rgba(0,0,0,0.4)'
}
}));
function User(props) {
const classes = useStyles();
const [checked, setChecked] = useState(false);
let table = {
data: [
{ name: "Patrick Mahomes", sector: "Quaterback", email: "patrick#nfl.com", tel: "1234" },
{ name: "Tom Brady", sector: "Quaterback", email: "tom#nfl.com", tel: "5678" },
{ name: "Julio Jones", sector: "Wide Receiver", email: "julio#nfl.com", tel: "9876" }
]
}
let config = {
columns: [
{ title: 'Name', field: 'name' },
{ title: 'Sector', field: 'sector' },
{ title: 'E-mail', field: 'email'},
{ title: 'Tel', field: 'tel'}
],
actions: [
{ icon: 'create', tooltip: 'Edit', onClick: (rowData) => alert('Edit')},
{ icon: 'lock', tooltip: 'Block', onClick: (rowData) => alert('Block')},
{ icon: 'delete', tooltip: 'Delete', onClick: (rowData) => alert('Delete')},
{ icon: 'visibility', tooltip: 'Access', onClick: (rowData) => alert('Access')},
{ icon: "add_box", tooltip: "Add", position: "toolbar", onClick: () => { alert('Add') } }
],
options: {
headerStyle: { color: 'rgba(0, 0, 0, 0.54)' },
actionsColumnIndex: -1,
exportButton: true,
paging: true,
pageSize: 10,
pageSizeOptions: [],
paginationType: 'normal'
},
localization: {
body: {
emptyDataSourceMessage: 'No data'
},
toolbar: {
searchTooltip: 'Search',
searchPlaceholder: 'Search',
exportTitle: 'Export'
},
pagination: {
labelRowsSelect: 'Lines',
labelDisplayedRows: '{from} to {to} for {count} itens',
firstTooltip: 'First',
previousTooltip: 'Previous',
nextTooltip: 'Next',
lastTooltip: 'Last'
},
header: {
actions: 'Actions'
}
}
}
useEffect(() => {
setChecked(prev => !prev);
async function loadUsers() {
const response = await api.get('/users');
table.data = response.data;
}
loadUsers();
}, [])
return (
<>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<Fade in={checked} style={{ transitionDelay: checked ? '300ms' : '0ms' }}>
<div className={classes.root}>
<MaterialTable editable={config.editable} options={config.options} localization={config.localization} title="Usuários" columns={config.columns} data={table.data} actions={config.actions}></MaterialTable>
</div>
</Fade>
</>
);
}
export default User;
The previous example will show 3 users that I fixed on variable table.data with 4 columns (name, sector, email, tel).
In a functional component, each render is really a new function call. So any variables you declare inside the component and destroyed and re-created. This means that table is set back to your initial value each render. Even if your useEffect is setting it correctly after the first render, it will just be reset on the next.
This is what state is for: to keep track of variables between renders. Replace your let table, with a new state hook.
const [table, setTable] = useState({
data: [
{ name: "Patrick Mahomes", sector: "Quaterback", email: "patrick#nfl.com", tel: "1234" },
{ name: "Tom Brady", sector: "Quaterback", email: "tom#nfl.com", tel: "5678" },
{ name: "Julio Jones", sector: "Wide Receiver", email: "julio#nfl.com", tel: "9876" }
]
});
Then use it like this:
useEffect(() => {
setChecked(prev => !prev);
async function loadUsers() {
const response = await api.get('/users');
setTable(prev => ({...prev, data: response.data});
}
loadUsers();
}, [])
Since table.data is not a state variable, it is regenerated as it was declared originally every time the component renders, meaning that by the time it arrives as a prop to your component it will always be the same value (when you change the value of table.data in useEffect it is too late). You need to change table.data to a state variable, and then in your useEffect hook you can update the value of table.data to the value of response.data. This will cause the component to be re-rendered but with the updated value.
Here's an example of how you might do that:
import React, { useState, useEffect } from 'react';
import { Fade } from "#material-ui/core";
import MaterialTable from 'material-table';
import { makeStyles } from '#material-ui/core/styles';
import api from '../../services/api.js';
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
width: '70%',
margin: 'auto',
marginTop: 20,
boxShadow: '0px 0px 8px 0px rgba(0,0,0,0.4)'
}
}));
function User(props) {
const classes = useStyles();
const [checked, setChecked] = useState(false);
const [tableData, setTableData] = useState([]);
let config = {
columns: [
{ title: 'Name', field: 'name' },
{ title: 'Sector', field: 'sector' },
{ title: 'E-mail', field: 'email'},
{ title: 'Tel', field: 'tel'}
],
actions: [
{ icon: 'create', tooltip: 'Edit', onClick: (rowData) => alert('Edit')},
{ icon: 'lock', tooltip: 'Block', onClick: (rowData) => alert('Block')},
{ icon: 'delete', tooltip: 'Delete', onClick: (rowData) => alert('Delete')},
{ icon: 'visibility', tooltip: 'Access', onClick: (rowData) => alert('Access')},
{ icon: "add_box", tooltip: "Add", position: "toolbar", onClick: () => { alert('Add') } }
],
options: {
headerStyle: { color: 'rgba(0, 0, 0, 0.54)' },
actionsColumnIndex: -1,
exportButton: true,
paging: true,
pageSize: 10,
pageSizeOptions: [],
paginationType: 'normal'
},
localization: {
body: {
emptyDataSourceMessage: 'No data'
},
toolbar: {
searchTooltip: 'Search',
searchPlaceholder: 'Search',
exportTitle: 'Export'
},
pagination: {
labelRowsSelect: 'Lines',
labelDisplayedRows: '{from} to {to} for {count} itens',
firstTooltip: 'First',
previousTooltip: 'Previous',
nextTooltip: 'Next',
lastTooltip: 'Last'
},
header: {
actions: 'Actions'
}
}
}
useEffect(() => {
setChecked(prev => !prev);
async function loadUsers() {
const response = await api.get('/users');
setTableData(response.data);
}
loadUsers();
}, [])
return (
<>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<Fade in={checked} style={{ transitionDelay: checked ? '300ms' : '0ms' }}>
<div className={classes.root}>
<MaterialTable editable={config.editable} options={config.options} localization={config.localization} title="Usuários" columns={config.columns} data={tableData} actions={config.actions}></MaterialTable>
</div>
</Fade>
</>
);
}
export default User;

Categories

Resources