I want to map through an array that is inside an object and see if the array contains the teacherId
and store it in a state, then map it so the <Section />
component can render it.
const teacherId = details.id;
const [availableSection, setAvailableSection] = useState([])
useEffect(() => {
const availSection = sections.map((section) => (
section.teachers.includes(teacherId) ? section : null
))
setAvailableSection(availSection);
}, [sections])
In the first transition to the "/dashboard"
page it returns an error, Uncaught TypeError: Cannot read properties of undefined (reading 'includes')
but if I refresh the page again it will render just fine. How can I fix this problem?
After going to the "/dashboard"
page, I want to instantly show the <Section />
component.
here's my code:
parent:
function Dashboard() {
const dispatch = useDispatch(getSections())
useEffect(() => {
dispatch(getSections());
}, [dispatch])
const location = useLocation()
return (
<>
<h1>Hello {location.state.teachersDetail.userName}</h1>
<h1>This is where the chart and cards are located</h1>
<Sections details={location.state.teachersDetail} />
</>
)
}
export default Dashboard;
Sections component:
function Sections({ details }) {
const sections = useSelector((state) => state.sections)
console.log(sections);
const teacherId = details.id;
const [availableSection, setAvailableSection] = useState([])
useEffect(() => {
const availSection = sections.map((section) => (
section.teachers.includes(teacherId) ? section : null
))
setAvailableSection(availSection);
}, [sections])
return (
!sections.length
? <CircularProgress />
: (
<Grid
container
direction="column"
justifyContent="flex-start"
alignItems="stretch"
style={{margin:'0 auto'}}
>
{availableSection.map((section) => (
section !== null
? (
<Grid key={section._id} item xs={12} sm={6}>
<Section section={section}/>
</Grid>
)
: null
))}
</Grid>
)
)
}
export default Sections
here's the section object:
sectionName: "ICT-5B", teachers: (3) ['1', '2', '3'], _id: "63f493ed77a87fdd1723d553"
section.teachers
is undefined. If you are really just wanting to filter the sections
array if there is a teachers
array that includes teacherId
then I suggest the following that uses a null-check on the potentially undefined section.teachers
property.
const sections = useSelector((state) => state.sections);
const teacherId = details.id;
const [availableSection, setAvailableSection] = useState([]);
useEffect(() => {
const availSection = sections.filter(
(section) => section.teachers?.includes(teacherId)
);
setAvailableSection(availSection);
}, [sections, teacherId]);
...
Also note that availableSection
is what we consider to be derived state and it's a general React anti-pattern to store derived state in local React state. Just about any time you have a useState/useEffect
pair what you really want to use is the useMemo
hook.
Example:
const sections = useSelector((state) => state.sections);
const teacherId = details.id;
const availableSection = useMemo(() => {
return sections.filter(
(section) => section.teachers?.includes(teacherId)
);
}, [sections, teacherId]);
...
If you don't need the selected sections
state other than to compute the availableSection
value then you can move the logic into the useSelector
hook.
Example:
const teacherId = details.id;
const availableSection = useSelector((state) => state.sections.filter(
(section) => section.teachers?.includes(teacherId)
));
...