I am trying to build an info panel in React that shows three items of latest activity from an online community. Mainly the latest people who have signed up to the community.
I currently have a list of the latest 30 signups being loaded from an API call into the dataArr constant as an array of JSX components. I then have a further useEffect that is triggered by the updating of the dataArr constant that saves the last 3 items from the dataArr into a further array constant call results. This is then displayed to the screen as a list of 3 items.
This works fine but my next step is to action the trimming of the dataArr by 1 item (the last item in the array) so that the display automatically updates to lose the last item in the list of 3 and to gain a new item. I will then be adding a nice animation transition effect so that the user can see what is happening.
I’ve created a test to make sure the logic works – testAction – that is called from an onClick action added to one of the JSX elements and here is where I’ve run into trouble. The dataArr constant is showing as empty from within the testAction function. It has lost its data.
I’ve added a new return to the page that has a hard-coded JSX element rather than those that are written from the array and when I call the testAction function from the static return the value in dataArr persists. However, when it is called from the actual return, the one generated from the “result” constant that contains the dynamically generated array-based JSX, the dataArr variable is always empty.
I ultimately want to run the testAction code at a 10 second interval using setInterval() and when I try actioning the code from setInterval() again the dataArr constant is empty.
What is causing the dataArr constant to lose its data? Is it something to do with me writing the JSX code into the array?
Any advice would be gratefully received.
import React, { createRef, forwardRef, useEffect, useState } from 'react'
import { Link, withRouter } from 'react-router-dom'
import { withAuth } from '../../AuthContext'
import {
Title,
PrimaryOutlineButton,
SubtitleOpen,
} from '../../Utils/CustomClasses'
import styled from 'styled-components'
const LatestActivityWrapper = styled.div`
margin: 0 0 40px 0;
`
const LatestActivityTitle = styled(Title)`
font-size: 18px !important;
`
const ActivityName = styled.div`
display: flex;
gap: 5px;
flex-wrap: nowrap;
`
const BreakSub = styled(SubtitleOpen)`
display: flex;
overflow-wrap: anywhere;
font-color: #941e15 !important;
font-family: 'Open Sans', sans-serif;
font-size: 18px;
font-weight: 400;
margin: 4px 0 0 0;
`
const BreakSubActivity = styled(BreakSub)`
width: 125px;
font-weight: 300;
font-size: 16px;
b {
font-weight: 600;
}
`
const BreakSubActivityRight = styled(BreakSubActivity)`
font-size: 16px;
width: -webkit-fill-available;
`
const ActivityText = styled(SubtitleOpen)`
font-family: 'Open Sans', sans-serif;
font-size: 16px;
font-weight: 300;
margin: 8px 0 0;
`
const LatestActivity = () => {
const [dataArr, setDataArr] = useState([])
const [results, setResults] = useState('')
const [test, setTest] = useState('')
useEffect(() => {
axios
.get(`/api/XXXXXXXXXXXXXXX/latestactivity`)
.then((response) => {
setTest('test text')
setDataArr(
response.data.map((d, index) => {
return (
<LatestActivityComponent
ref={createRef()}
key={index}
u={d.forename}
country={d.country.nicename}
activityType={'SIGNUP'}
color={'#3DBD7E'}
activityText={
d.forename + ' signed up from ' + d.country.nicename
}
/>
)
})
)
})
.catch((err) => {
console.log('Error getting latest featured activity: ', err)
})
}, [])
useEffect(() => {
console.log('dataArr: ' + JSON.stringify(dataArr))
setResults(dataArr.slice(dataArr.length - 3, dataArr.length))
}, [dataArr])
const testAction = () => {
console.log('testAction....')
console.log('test: ' + test)
console.log('dataArr: ' + dataArr)
console.log('test: ' + test)
console.log('dataArr.length: ' + dataArr.length)
const newData = dataArr.pop()
console.log('dataArr.length: ' + dataArr.length)
console.log('dataArr: ' + dataArr)
setDataArr(dataArr)
}
const LatestActivityComponent = forwardRef(
({ u, country, activityType, color, activityText }, ref) => {
return (
<LatestActivityWrapper ref={ref}>
<LatestActivityTitle color={color} size="18px">
{activityType}
</LatestActivityTitle>
<ActivityName>
<BreakSubActivity onClick={() => testAction()}>
<b>Name:</b>
</BreakSubActivity>
<BreakSubActivityRight>{u}</BreakSubActivityRight>
</ActivityName>
<ActivityName>
<BreakSubActivity>
<b>Location:</b>
</BreakSubActivity>
<BreakSubActivityRight>{country}</BreakSubActivityRight>
</ActivityName>
<ActivityText>{activityText}</ActivityText>
</LatestActivityWrapper>
)
}
)
if (!results || test == '') {
return (
<div className="card-body text-center">
<div
className="spinner-border homestays-spinner"
style={{ margin: '100px auto 100px', opacity: '0.3' }}
role="status"
></div>
</div>
)
}
// The testAction function does not work from here
//return results
// The testAction function works from here
return (
<BreakSubActivity onClick={() => testAction()}>
aaa - {test}
</BreakSubActivity>
)
}
export default withRouter(withAuth(LatestActivity))
1
dataArr.pop()
will mutate dataArr. slice(0, -1)
can be used instead; it returns a copy of the original array without the last element.
A minimal version of testAction
can look like this:
const testAction = () => {
setDataArr(prev => prev.slice(0, -1))
}
1