Доступ к реквизитам / атрибутам из дочернего компонента с помощью хуков - PullRequest
0 голосов
/ 25 сентября 2019

Я пытаюсь создать функцию, позволяющую легко скрывать / показывать все элементы (подкомпоненты).Используя useState, я могу установить, все ли элементы скрыты / показаны.Используя useEffect, я могу переключать предметы, которые скрыты / показаны.У меня проблемы с доступом к реквизитам в подкомпоненте, чтобы определить, был ли элемент уже расширен.Я хотел бы объяснить это лучше, но, надеюсь, этот пример кодирования раскроет лучшую картинку.

index.js

import React, { useState } from "react";
import ReactDOM from "react-dom";
import "semantic-ui-css/semantic.min.css";
import { Button } from "semantic-ui-react";
import Item from "./Item";

const Services = props => {
  const [allExpanded, setAllExpanded] = useState(false);

  return (
    <>
      <p>
        <Button onClick={() => setAllExpanded(false)} content="Hide all" />
        <Button onClick={() => setAllExpanded(true)} content="Show all" />
      </p>
      <p>
        <Item expanded={allExpanded} />
        <Item expanded={allExpanded} />
        <Item expanded={allExpanded} />
      </p>
    </>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<Services />, rootElement);

Item.js

import React, { useState, useEffect } from "react";
import { Accordion } from "semantic-ui-react";

const Item = props => {
  const [expanded, setExpanded] = useState(props.expanded);

  useEffect(() => {
    setExpanded(props.expanded);
  }, [props.expanded]);

  return (
    <Accordion styled>
      <Accordion.Title
        onClick={() => {
          setExpanded(!expanded);
        }}
      >
        <p>{expanded ? "- Hide Item" : "+ Show Item"}</p>
      </Accordion.Title>
      <Accordion.Content active={expanded}>Lorem ipsum...</Accordion.Content>
    </Accordion>
  );
};

export default Item;

CodeSandbox

Чтобы воспроизвести мою текущую ошибку, нажмите любой «+ Показать элемент», затем нажмите «Скрыть все».Он не будет скрывать все, однако, нажав «Показать все», затем «Скрыть все» скроет все.

Ответы [ 3 ]

1 голос
/ 25 сентября 2019

Вы сталкиваетесь с этой проблемой, потому что ваш родительский компонент на самом деле имеет три возможных состояния:

  • Все развернуто
  • Все свернуто
  • Ни все развернуто, ни свернуто

Чтобы отразить третье состояние, вы можете использовать null / undefined (и передать установщик в дочерние компоненты).

Обновленный пример здесь: https://codesandbox.io/s/competent-villani-i6ggh

0 голосов
/ 25 сентября 2019

Вот код и песочница, разветвленная от вашего:

https://codesandbox.io/s/competent-wildflower-n0hb8

Я изменил его так, чтобы вместо чего-то вроде этого:

let [allExpanded, setAllExpanded] = useState(true) 

У вас есть что-токак это:

let [whichExpanded, setWhichExpanded] = useState({0: true, 1:true, 2: true})

Затем, для вашего обратного вызова, чтобы развернуть / свернуть все кнопки, у вас есть это:

<button onClick=()=>{
    let newState = {}
    for(let order in whichEpanded){
       newState[order] = false //change every key to false
    }
    setAllExpanded(newState)
}> hide all</button>

Затем я передал реквизит «порядка» вашемуПредметы.Свойство "order" используется в качестве аргумента для функции обратного вызова, которую я передаю, поэтому, когда вы нажимаете на каждый элемент, он обновляет состояние whichExpanded, чтобы переключать видимость только этого одного элемента.

 // pass this to eac of the items:
 const setIndividualItemExpanded = order => {
    let newItemsExpandedState = { ...itemsExpanded };
    newItemsExpandedState[order] = !newItemsExpandedState[order];
    setItemsExpanded(newItemsExpandedState);
  };

Каждый компонент элемента:

  <Item
      expanded={itemsExpanded[0]} //is reading from the state
      order={0}
      setExpanded={setIndividualItemExpanded}
    />

Затем вы можете удалить useState из визуализированного компонента и просто обновить его с помощью "setExpanded" prop

(полный код в кодах и коробке вставлен сверху)

0 голосов
/ 25 сентября 2019

Поскольку вы обрабатываете расширенное состояние ваших аккордеонов на верхнем уровне, я предлагаю вам просто передать расширенное состояние и «переключатель» вашим элементам.index.js будет обрабатывать логику, а ваш Item компонент будет презентационным.

Вот ответвление вашего CodeSandbox .

Это не выглядит великолепно и, вероятно,состояние элемента и переключение можно (и, вероятно, следует) перенести в другое место (например, отдельный редуктор с использованием useReducer hook )

Если вы планируете создать эти компонентыдинамически, IMO, это самый простой способ.

Если вы все еще хотите идти своим путем, вы можете реорганизовать свой Item в компонент класса и использовать Refs , чтобы получить их текущийоднако я не рекомендую такой подход.

Надеюсь, это поможет!

...