Answer the question
In order to leave comments, you need to log in
How to optimize calculations in a functional component?
Wrote a component that calculates different values. The data arrives constantly through the websocket and is calculated in useEffect.
Here is what the customer sent me:
will fall because the memory will run out and will not be able to work as required in the task, for weeks or months
, and when a lot of data is collected, it will take a very long time to count
and should give an answer within a second after pressing the button
...
export const Statistics = () => {
const [data, setData] = useState([])
const [average, setAverage] = useState('')
const [calculationTime, setCalculationTime] = useState(0)
const [standardDeviation, setStandardDeviation] = useState('')
const [modes, setModes] = useState('')
const [median, setMedian] = useState('')
const [statistic, setStatistic] = useState(0)
const [isConnectionStarted, setIsConnectionStarted] = useState(false)
const ws = useRef(null);
// ----------вычисления ----------
const getAverageScores = () => {
const initialValues = {avg: 0, n: 0};
return data.reduce(function (initialValues, data) {
const avg = (data.value + initialValues.n * initialValues.avg) / (initialValues.n + 1)
const n = initialValues.n + 1
return {
avg,
n
}
}, initialValues).avg;
}
const getStandardDeviation = () => {
const total = 0;
const averageScore = getAverageScores()
const squaredDeviations = data.reduce(function (total, data) {
const deviation = data && data.value - averageScore;
const deviationSquared = deviation * deviation;
return total + deviationSquared;
}, total);
return Math.sqrt(squaredDeviations / data.length);
}
const getModes = () => {
let frequency = [];
let maxFreq = 0;
let modes = [];
for (let i in data){
frequency[data[i].value] = (frequency[data[i].value] || 0) + 1;
if (frequency[data[i].value] > maxFreq) {
maxFreq = frequency[data[i].value];
}
}
for (let j in frequency) {
if (frequency[j] === maxFreq) {
modes.push(j);
}
}
if ( maxFreq === 1) {
return ' - '
}
if (!modes.length) {
return ' - '
}
return modes.join(', ')
}
const getMedian = () => {
data.sort(function (a, b) {
return a.value - b.value;
});
const half = Math.floor(data.length / 2);
if (data.length % 2) {
return data[half].value;
}
return (data[half - 1].value + data[half].value) / 2;
}
const calculation = () => {
const startTime = new Date().getTime();
setAverage(getAverageScores())
setStandardDeviation(getStandardDeviation())
setModes(getModes())
setMedian(getMedian())
const finishTime = new Date().getTime();
setCalculationTime(finishTime - startTime)
}
// ----------Зыпускаю вычисления при обновлении данных ----------
useEffect(() => {
if (data.length) {
calculation()
}
}, [data])
// ----------Коннекчусь к серверу----------
const start = () => {
ws.current = new WebSocket('wss://trade.trademux.net:8800/?password=1234');
if (isConnectionStarted) {
ws.current.close()
setData([])
setStatistic(0)
}
ws.current.onopen = () => {
console.log('ws opened');
setIsConnectionStarted(true)
}
ws.current.onclose = () => {
setIsConnectionStarted(false)
}
ws.current.onmessage = e => {
const message = JSON.parse(e.data);
setData(oldData => [...oldData, message])
}
}
// ----------Расконекчиваюсь с сервером ----------
useEffect(() => {
return () => {
ws.current.close();
};
}, []);
const getStatistic = () => {
setStatistic(prevState => prevState + 1)
}
return (
<>
<div className="quote-statistics">
<Item value={Boolean(statistic) && average}/>
<Item value={Boolean(statistic) && standardDeviation}/>
<Item value={Boolean(statistic) && modes}/>
<Item value={Boolean(statistic) && median}/>
<Item value={Boolean(statistic) && calculationTime}/>
</div>
<div className="quote-statistics_ctrl">
<Btn func={start} title='START'/>
<Btn func={getStatistic} title='STAT'/>
</div>
</>
)
}
Answer the question
In order to leave comments, you need to log in
What a wonderful code, the blood from the eyes went already from the first function. I'll sign it, I won't have enough for more.
const getAverageScores = () => {
const initialValues = {avg: 0, n: 0};
return data.reduce(function (initialValues, data) {
const avg = (data.value + initialValues.n * initialValues.avg) / (initialValues.n + 1)
const n = initialValues.n + 1
return {
avg,
n
}
}, initialValues).avg;
}
return data.reduce((acc, { value }) => acc + value, 0) / data.length;
In addition to the analysis of functions made by WbICHA (severe, but fair), I’ll throw in more purely Reakt points:
1) functions with calculations to evict the hell out of the component, pass data to them.
2) A bunch of states (average... median) - nothing more than blasphemous derivative states to be reforged into useMemo, with the useEffect containing calculation() thrown into the trash.
3) isConnectionStarted looks like an extra one. At least it's not a state. Perhaps it should be changed to ref
4) The purpose of statistic is not clear. I suspect that it is not needed, since it duplicates data.length (a sign of data availability).
5) It would be nice to work with a websocket in a separate class with logic. Store an instance of the class, for example, in ref.
6) in the start function there is some heresy inside ifa
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question