Не происходит рендера элемента, хотя он отображается
У меня есть выпадающий список с контейнером DropDown. В контейнере есть Group`ы. Элемент DroupDown рендерится когда меняется глобальный state и с сервера приходят необходимые данные:
const groupsWithData = useSelector(store => { return store.persons.structurePersons })
useEffect(() => {
if (groupsWithData) {
setGroupElem(groupsWithData.map((item) => {
return <Group
key={item.group_id}
groupName={item.group_name}
idGroup={item.group_id}
positionData={item.group_data}
isOpen={item.group_isOpen}
handleToggleVisibleGroup={handleToggleVisibleGroup}
/>
}))
}
},[groupsWithData])
При этом в элемент Group передается много всего. Group - это тоже элемент со вложенными элементами. Помимо данных из State в Group передается ф-ия handleToggleVisibleGroup, которая должна менять признак открыта ли группа или закрыта по клику на Group. Что происходит у меня - у меня рендерится DropDown и, как я предполагал, рендерятся все Group, так как я могу развернуть DropDown и увидеть все вложенные Groups, согласно глобальному State... Я запускаю ф-ию
handleToggleVisibleGroup по клику на Group.
const handleToggleVisibleGroup = (groupId) => {
dispatch(toggleVisiblePosition(groupId))
}
У меня срабатывает редьюсер и в State меняются данные согласно задуманному... НО перерендера не происходит... посмотрел на данные и девтул и удивился... Group вообще не рендерится... я не понимаю, что происходит
Весь компонент DropDown:
import React, { useState, useEffect } from "react";
import './DropDown.css'
import Group from "../Group/Group";
import Button from "../Button/Button";
import {useDispatch, useSelector} from 'react-redux';
import { toggleVisiblePosition } from '../../redux/actions';
const DropDown = () => {
const dispatch = useDispatch();
const [isVisibleDopDown, setIsVisibleDropDown] = useState(false)
const [groupElem, setGroupElem] = useState(<Group/>)
const groupsWithData = useSelector(store => { return store.persons.structurePersons })
const handleToggleVisibleGroup = (groupId) => {
dispatch(toggleVisiblePosition(groupId))
}
useEffect(() => {
if (groupsWithData) {
setGroupElem(groupsWithData.map((item) => {
return <Group
key={item.group_id}
groupName={item.group_name}
idGroup={item.group_id}
positionData={item.group_data}
isOpen={item.group_isOpen}
handleToggleVisibleGroup={handleToggleVisibleGroup}
/>
}))
}
},[groupsWithData])
const toggleVisibleDropDown = (e) => {
setIsVisibleDropDown(!isVisibleDopDown)
}
return (
<div className="drop-down">
<Button
handleClick={toggleVisibleDropDown}
cusStyle={`button button_drop-down-menu ${isVisibleDopDown === true ? 'button_drop-down-menu_visible' : ''}`}
text={'Сотрудники'}
/>
<ul className={`drop-down__container ${isVisibleDopDown === true ? 'drop-down__container_visible' : ''}`}>
{groupElem}
</ul>
</div>
)
}
export default DropDown;
Компонент Group
import './Group.css'
import React from "react";
import Checkbox from "../Checkbox/Checkbox";
import Position from "../Position/Position";
import arrow from "../../img/arrow.png";
import uniq from 'uniqid';
const Group = ({ groupName, positionData, idGroup, isOpen, handleToggleVisibleGroup }) => {
return (
<li onClick={() => handleToggleVisibleGroup(idGroup)} className="group">
<div className="group__header">
<Checkbox label={groupName} />
<img className="group__header-img" src={arrow} alt="" />
</div>
<ul className={`group__items-list ${isOpen === true ? 'group__items-list_visible' : ''}`}>
{
positionData.map((item) => {
const keyId = uniq()
return <Position
id={keyId}
key={keyId}
label={item.position_name}
persons={item.persons}
/>
})
}
</ul>
</li>
)
}
export default Group;
Так же добавил то, как отображается state. Видно, что при клике по Group свойство group_isOpen стало true, но отобразится это только после того, как я закрою и открою заново DropDown
Код редьюсера:
import personsUtils from '../utils/personsUtils';
import { GET_ALL_PERSONS, TOGGLE_VISIBLE_POSITION } from "./types"
const initialState = {
mainStatePersons: [],
structurePersons: []
}
export const persons = (state=initialState, action) => {
switch(action.type) {
case GET_ALL_PERSONS:
const persons = personsUtils.setId(action.allPersons)
const positions = personsUtils.getPositionsPerson(persons);
return {
...state,
mainStatePersons: persons,
structurePersons: positions
}
case TOGGLE_VISIBLE_POSITION:
state.structurePersons.some((item) => {
if (item.group_id === action.id) {
item.group_isOpen = !item.group_isOpen;
return true
}
return false
})
return {
...state
}
default:
return state
}
}
Ответы (1 шт):
У вас уже есть источник данных, ваш стор redux'а, дополнительно к этому наращивать useState нет никакого смысла.
См. комментарии ниже.
p.s.Для формирования списка имен классов используйте библиотеку classnames
import React, { useState, useEffect } from "react";
import "./DropDown.css";
import Group from "../Group/Group";
import Button from "../Button/Button";
import { useDispatch, useSelector } from "react-redux";
import { toggleVisiblePosition } from "../../redux/actions";
const DropDown = () => {
const dispatch = useDispatch();
//получили данные
const groupsWithData = useSelector((store) => {
return store.persons.structurePersons;
});
const [isVisibleDopDown, setIsVisibleDropDown] = useState(false);
//const [groupElem, setGroupElem] = useState(<Group />) зачем оно здесь?;
const handleToggleVisibleGroup = (groupId) => {
dispatch(toggleVisiblePosition(groupId));
};
/*
не нужен
useEffect(() => {
if (groupsWithData) {
setGroupElem(
groupsWithData.map((item) => {
return (
<Group
key={item.group_id}
groupName={item.group_name}
idGroup={item.group_id}
positionData={item.group_data}
isOpen={item.group_isOpen}
handleToggleVisibleGroup={handleToggleVisibleGroup}
/>
);
})
);
}
}, [groupsWithData]);*/
const toggleVisibleDropDown = (e) => {
setIsVisibleDropDown(!isVisibleDopDown);
};
return (
<div className="drop-down">
<Button
handleClick={toggleVisibleDropDown}
cusStyle={`button button_drop-down-menu ${
isVisibleDopDown === true ? "button_drop-down-menu_visible" : ""
}`}
text={"Сотрудники"}
/>
<ul
className={`drop-down__container ${
isVisibleDopDown === true ? "drop-down__container_visible" : ""
}`}
>
{
//сразу строим компоненты
groupsWithData.map((item) => {
return (
<Group
key={item.group_id}
groupName={item.group_name}
idGroup={item.group_id}
positionData={item.group_data}
isOpen={item.group_isOpen}
handleToggleVisibleGroup={handleToggleVisibleGroup}
/>
);
})
}
</ul>
</div>
);
};
export default DropDown;
upd. по Group
Встречал подобную проблему, когда делал зависимости имен классов от пропсов.
Попробуйте вообще не рендерить элемент, если isOpen = false (см. пример ниже), либо используйте classnames (ссылка выше)
import "./Group.css";
import React from "react";
import Checkbox from "../Checkbox/Checkbox";
import Position from "../Position/Position";
import arrow from "../../img/arrow.png";
import uniq from "uniqid";
const Group = ({
groupName,
positionData,
idGroup,
isOpen,
handleToggleVisibleGroup,
}) => {
return (
<li onClick={() => handleToggleVisibleGroup(idGroup)} className="group">
<div className="group__header">
<Checkbox label={groupName} />
<img className="group__header-img" src={arrow} alt="" />
</div>
{
//если isOpen = false, то не рендерим
isOpen && (
<ul className={`group__items-list group__items-list_visible`}>
{positionData.map((item) => {
const keyId = uniq();
return (
<Position
id={keyId}
key={keyId}
label={item.position_name}
persons={item.persons}
/>
);
})}
</ul>
)}
</li>
);
};
export default Group;

