0

I want to get the heights of the rendered list items into an array stored in a parent component. It looks fairly simple but still it does not work. From what I see when debugging, the dispatch is fired and the reducer receives the action, but yet the state remains as empty array.

ArticlesMenu.js

import React, { useRef, useState, useEffect, useReducer } from 'react';
import ArticlesMenuItem from './ArticlesMenuItem';

    const reducer = (state, action) => {
        console.log('action', action)
        switch (action.type) {
            case 'add-height': 
                return [...state, action.payload];
            default:
                return state
        }
    }
    
    const ArticlesMenu = ({ articleItems }) => {
        const initialState = [0];
        const [state, dispatch] = useReducer(reducer, initialState);
        const [height, setHeight] = useState('auto'); 
        const renderArticles = () => {
            return articleItems && articleItems.items.map((item, index) => {
                return (
                    <ArticlesMenuItem 
                        path={item.path}    
                        height={height}
                        label={item.label}
                        key={item.id}
                        getHeights={(refHeight) => {
                            console.log('refHeight', refHeight)
                            dispatch({type: 'add_height', payload: refHeight})
                        }}
                    />
                )
            });
        }
    
        console.log('state', state)
    
        return (
            <div id="articles" className="clearfix">
                <h2 className="articles__heading">{articleItems && articleItems.heading}</h2>
                <ul className="articles__list">
                    {renderArticles()}
                </ul>
            </div>
        )
    }
    
    export default ArticlesMenu

ArticlesMenuItem.js

import { useRef, useEffect, useState } from 'react';
import { Link } from 'react-router-dom';

const ArticlesMenuItem = ({ path, id, label, height, getHeights}) => {
    const ref = useRef();

    useEffect(() => {
        getHeights(ref.current.clientHeight)
    },[])

    return (
        <li className="articles__item" ref={ref} style={{height: height}}>
            <Link to={path} className="articles__link" >{label}</Link>
        </li>
    )
}

export default ArticlesMenuItem;
bakrall
  • 465
  • 7
  • 21

1 Answers1

0

Your dispatch action type is 'add_height' but in your reducer the action type is 'add-height' so the way use default that return state and your initial state is an empty array. You need to change your dispatch action type for same string that reducer annotation. For not reproduce this error use a reference (const ADD_HEIGHT_ACTION = 'add-height' and use on reducer and dispatch.

LutherW
  • 359
  • 2
  • 6
  • thanks a lot! I used `useReducer` for the first time and I was to quickly making assumption that I misunderstood it. Looks like I rather need rest ;) – bakrall Feb 19 '22 at 22:35
  • Classic, use const ref every time you use the same string reference to prevent this type error. Good code ! – LutherW Feb 19 '22 at 22:41
  • True, @LutherW, thanks for good advice! – bakrall Feb 21 '22 at 19:10