Luaskan / Ciutkan semua data

Sep 29 2020

Saya membuat Accordion dan ketika kita mengklik masing-masing item maka pembukaan atau penutupannya dengan baik.

Sekarang saya telah menerapkan perluas semua atau tutup semua opsi untuk itu untuk membuat semua akordeon berkembang / runtuh.

Accordion.js

  const accordionArray = [
    { heading: "Heading 1", text: "Text for Heading 1" },
    { heading: "Heading 2", text: "Text for Heading 2" },
    { heading: "Heading 3", text: "Text for Heading 3" }
  ];
  .

  .

  .
{accordionArray.map((item, index) => (
        <div key={index}>
          <Accordion>
            <Heading>
              <div className="heading-box">
                <h1 className="heading">{item.heading}</h1>
              </div>
            </Heading>
            <Text expandAll={expandAll}>
              <p className="text">{item.text}</p>
            </Text>
          </Accordion>
        </div>
      ))}

Dan text.js adalah file tempat saya melakukan tindakan untuk membuka konten tertentu dari akordeon dan kode sebagai berikut,

import React from "react";

class Text extends React.Component {
  render() {
    return (
      <div style={{ ...this.props.style }}>
        {this.props.expandAll ? (
          <div className={`content open`}>
            {this.props.render && this.props.render(this.props.text)}
          </div>
        ) : (
          <div className={`content ${this.props.text ? "open" : ""}`}>
            {this.props.text ? this.props.children : ""}
            {this.props.text
              ? this.props.render && this.props.render(this.props.text)
              : ""}
          </div>
        )}
      </div>
    );
  }
}

export default Text;

Di sini melalui this.props.expandAllsaya mendapatkan nilai apakah expandAll itu benar atau salah. Jika benar maka semua akordeon akan mendapatkan kelas className={`content open`}sehingga semua akan terbuka.

Masalah:

The openkelas diterapkan namun isi teks di dalam tidak diberikan.

Jadi baris ini tidak berfungsi,

{this.props.render && this.props.render(this.props.text)}

Kebutuhan:

Jika tombol perluas semua / ciutkan semua diklik maka semua akordeon harus dibuka / ditutup masing-masing.

Ini harus berfungsi terlepas dari akordeon yang dibuka / ditutup sebelumnya .. Jadi jika Perluas semua maka harus membuka semua akordeon atau harus menutup semua akordeon meskipun sebelumnya telah dibuka / ditutup.

Tautan:

Ini adalah tautan file tersebut https://codesandbox.io/s/react-accordion-forked-sm5fw?file=/src/GetAccordion.js di mana alat peraga sebenarnya diturunkan.

Edit:

Jika saya menggunakan {this.props.children}maka setiap akordeon akan terbuka .. Tidak ada masalah.

Tetapi jika saya membuka akordeon secara manual saat mengklik item tertentu maka Jika saya mengklik perluas semua maka diperluas (diharapkan) tetapi Jika saya klik kembali Tutup semua opsi maka tidak semua akordeon ditutup .. Yang kita buka sebelumnya masih ada di keadaan terbuka .. Tetapi perilaku yang diharapkan di sini adalah bahwa semuanya harus ditutup.

Jawaban

onkar_osj Sep 29 2020 at 21:26

Di file Anda text.js

pada baris nomor 9. silahkan ganti kode sebelumnya dengan: {this.props.children}

Mencoba di kotak pasir dan bekerja untuk saya.

/// tidak bisa menambahkan komentar jadi mengedit jawabannya sendiri. Accordian.js berisi hook Anda expandAll dan heading boolean sudah terjadi GetAccordian.js. Saya sarankan untuk memindahkan semua perluasan ke GetAccordian.js sehingga Anda dapat mengontrol kedua nilai.

lissettdm Sep 29 2020 at 21:14

dalam hal ini this.props.render bukan sebuah fungsi dan this.props.text tidak ditentukan, coba ganti baris ini

  <div className={`content open`}>
    {this.props.render && this.props.render(this.props.text)}
  </div>

dengan ini:

  <div className={`content open`}>
   {this.props.children}
  </div>

EDIT: // Solusi lainnya adalah meneruskan properti expandAll ke komponen Accordion

  <Accordion expandAll={expandAll}>
    <Heading>
      <div className="heading-box">
        <h1 className="heading">{item.heading}</h1>
      </div>
    </Heading>
    <Text>
      <p className="text">{item.text}</p>
    </Text>
  </Accordion>

lalu di getAccordion.js

onShow = (i) => {
      this.setState({
        active: this.props.expandAll ? -1: i,
        reserve: this.props.expandAll ? -1: i
      });

      if (this.state.reserve === i) {
        this.setState({
          active: -1,
          reserve: -1
        });
      }
    };

    render() {
      const children = React.Children.map(this.props.children, (child, i) => {
        return React.cloneElement(child, {
          heading: this.props.expandAll || this.state.active === i,
          text: this.props.expandAll || this.state.active + stage === i,
          onShow: () => this.onShow(i)
        });
      });
      return <div className="accordion">{children}</div>;
    }
  };
goodmorningasif Sep 29 2020 at 22:47

Membangun dari jawaban @lissettdm, tidak jelas bagi saya mengapa getAccordiondan accordionmerupakan dua entitas yang terpisah. Anda mungkin memiliki alasan yang sangat valid untuk pemisahan tersebut, tetapi fakta bahwa status kedua komponen saling bergantung mengisyaratkan bahwa mereka mungkin lebih baik diimplementasikan sebagai satu komponen.

Accordion sekarang mengontrol status turunannya secara langsung, seperti sebelumnya, tetapi tanpa menggunakan getAccordion. Toggling expandAll sekarang menyetel ulang status masing-masing item juga.

const NormalAccordion = () => {
  const accordionArray = [ //... your data ];

  const [state, setState] = useState({
    expandAll: false,
    ...accordionArray.map(item => false),
  });

  const handleExpandAll = () => {
    setState((prevState) => ({
      expandAll: !prevState.expandAll,
      ...accordionArray.map(item => !prevState.expandAll),
    }));
  };

  const handleTextExpand = (id) => {
    setState((prevState) => ({
      ...prevState,
      [id]: !prevState[id]
    }));
  };

  return (
    <>
      <div className="w-full text-right">
        <button onClick={handleExpandAll}>
          {state.expandAll ? `Collapse All` : `Expand All`}
        </button>
      </div>
      <br />
      {accordionArray.map((item, index) => (
        <div key={index}>
          <div className="accordion">
            <Heading handleTextExpand={handleTextExpand} id={index}>
              <div className="heading-box">
                <h1 className="heading">{item.heading}</h1>
              </div>
            </Heading>
            <Text shouldExpand={state[index]}>
              <p className="text">{item.text}</p>
            </Text>
          </div>
        </div>
      ))}
    </>
  );
};

Heading mengembalikan indeks sehingga komponen induk mengetahui item mana yang harus dinonaktifkan.

class Heading extends React.Component {
  handleExpand = () => {
    this.props.handleTextExpand(this.props.id);
  };


  render() {
    return (
      <div
        style={ //... your styles}
        onClick={this.handleExpand}
      >
        {this.props.children}
      </div>
    );
  }
}

Teks hanya peduli pada satu prop untuk menentukan apakah itu harus menampilkan konten yang diperluas.

class Text extends React.Component {
  render() {
    return (
      <div style={{ ...this.props.style }}>
        <div
          className={`content ${this.props.shouldExpand ? "open" : ""}`}
        >
          {this.props.shouldExpand ? this.props.children : ""}
        </div>
      </div>
    );
  }
}