Mam następujący kod, który w zasadzie upada wszystkie podmenu i otwiera je tylko po kliknięciu:

<ul class="menu">
  <li>
    <a href="#">One</a>
    <ul class="menu">
      <li>
        <a href="#">Alpha</a>
        <ul class="menu">
          <li><a href="#">Hello</a></li>
          <li><a href="#">World</a></li>
        ...
      <li><a href="#">Beta</a></li>
    </ul>
  </li>
  <li><a href="#">Three</a></li>
</ul>

<script type="text/javascript">
  $(".menu").children().click(function(e) {
    $(this).siblings().find("ul").hide();
    $(this).children().show();
  });
</script>

Użyłem funkcji rekurencyjnej, aby utworzyć menu z API podmenu z DRF i pomyślnie udało się wyświetlić menu z tego API z następującym kodem:

class Recursive extends React.Component {
    render() {
        let childitems = null;

        if (this.props.children) {
            childitems = this.props.children.map(function(childitem) {
                return (
                    <Recursive item={childitem} children={childitem.children} />
                )
            })
        }
        return (
            <li key={this.props.item.id}>
                {this.props.item.name}
                { childitems ? <ul>{childitems}</ul> : null }
            </li>
        );
    }
}


class MenuDisplay extends React.Component {
    render() {
        let items = this.props.data.map(function(item) {
            return (
                <Recursive item={item} children={item.children} />
            )
        })
        return (
            <ul>
                {items}
            </ul>
        );
    }
}

Jak mogę zrekomczyć mój kod reagowania, aby uwzględnić funkcję, którą stworzyłem z jQuery w pierwszym przykładzie?

Oto JSFiddle dla HTML.

0
MiniGunnR 3 czerwiec 2018, 21:08

3 odpowiedzi

Najlepsza odpowiedź

Twój rekurencyjny składnik menu można zmniejszyć do pojedynczego komponentu tak prostego jak:

import React, { Component } from "react";

class Menu extends Component {
    state = {
        // initially no item is active
        active: null
    };

    // when clicked store the item id as active
    handleClick = id => this.setState({ active: id });

    render() {
        const { links } = this.props;
        const { active } = this.state;

        return (
            <ul className="menu">
                {links.map(({ id, name, children }) => (
                    <li key={id} onClick={() => this.handleClick(id)}>
                        {name}
                        {/* only render the children links when */}
                        {/* the item is the active one and the */}
                        {/* item actually has children */}
                        {id === active && children && (
                            <Menu links={children} />
                        )}
                    </li>
                ))}
            </ul>
        );
    }
}

I używaj go jak:

const LINKS = [
    {id: 'one', name: 'One', children: [
        {id: 'alpha', name: 'Alpha', children: [
            {id: 'hello', name: 'Hello'},
            {id: 'world', name: 'World'},
        ]},
        {id: 'beta', name: 'Beta'},
    ]},
    {id: 'two', name: 'Two'},
]

ReactDOM.render(<Menu links={LINKS} />, document.getElementById('root'));

Sprawdź Przykład roboczy , aby zobaczyć go w akcji:

Edit jn6vqn5jzy

Funkcjonalność jQuery jest osiągana dzięki dokonaniu każdego rekurencyjnego komponentu menu skupić aktywny link jako stan i uczynić tylko dzieciami tego linku do aktywnego elementu.

Zauważ, że nie musisz ukrywać elementów z reagującą. Nie uczyniasz ich w pierwszej kolejności, jeśli nie powinny być wyświetlane. W tym przykładzie jest to sprawdzane, porównując aktywny identyfikator z identyfikatorem elementu, który powinien być renderowany. Jeśli pasuje do -> Renderuj podłącza.

2
trixn 3 lipiec 2018, 22:59

Wyciągnąłem przykład pracy z tym, co myślę, że chcesz w reagować, ponieważ nie mam życia i nic do zrobienia dzisiaj :)

Krótko mówiąc, jest kilka sposobów na to, ale myślę, że najlepszym sposobem jest stworzenie oddzielnego składnika reagowania, który zdecyduje się wyświetlić lub ukryć komponent dziecięcy na podstawie jego stanu. Może wyglądać na wiele więcej kodu niż rozwiązanie jQuery, ale może to rozwiązać pewne problemy związane z prowadzeniem, które mogą pochodzić z ukrywania się i pokazywania rzeczy z CSS. W każdym razie oto Fiddle Link i wkleję kod poniżej.

class Menu extends React.Component{
    constructor(props){
    super(props);
    this.state = {
        open: false
    }

    this.toggleDropDown = this.toggleDropDown.bind(this);
  }

  toggleDropDown(){
    // this toggles the open state of the menu
    this.setState({open: !this.state.open})
  }

  render(){
    // only display children if open is true
    return(
        <ul className="menu">
        <li onClick={this.toggleDropDown}>         {this.props.title}  </li>
        {(this.state.open)?this.props.children:null}
        </ul>
    )
  }
}

class Hello extends React.Component {
  render() {
    return (
    <div>
      <Menu title="one">
        <Menu title="Alpha">
          <ul>
            <li>Hello</li>
            <li>World</li>
          </ul>
        </Menu>
        <Menu title="Beta">
          <ul>
            <li>Hello</li>
            <li>World</li>
          </ul>
        </Menu>
      </Menu>  
      <Menu title="two">
      <ul>
        <li>Alpha</li>
        <li>Beta</li>
        </ul>
      </Menu>
      <ul className="menu">
      <li>three</li>
      <li>four</li>
      </ul>
    </div>
    );
  }
}

ReactDOM.render(
  <Hello name="World" />,
  document.getElementById('container')
);
1
Michael Sorensen 3 czerwiec 2018, 19:11

Na podstawie kodu Michaela Sorensena podniosłem stan i zmodyfikowałem kod. Wynik RUN jest prawie taki sam jak kod jQuery, z wyjątkiem tego, że jeśli klikniesz "One", pojawią się tylko natychmiastowe dzieci. Chciałbym, więc go tam zostawiłem. Kod jest wklejony poniżej.

function Menu(props) {
  return (
    <ul className="menu">
      <li onClick={props.onClick}> {props.title} </li>
      {props.open ? props.children : null}
    </ul>
  );
}

class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: Array(2).fill(false),
      open2: Array(2).fill(false)
    };

    this.toggleDropDown = this.toggleDropDown.bind(this);
    this.toggleDropDown2 = this.toggleDropDown2.bind(this);
  }

  toggleDropDown(i) {
    const open = Array(2).fill(false);
    this.setState({
      open: open.fill(true, i, i + 1),
      open2: Array(2).fill(false)
    });
  }
  toggleDropDown2(i) {
    const open2 = Array(2).fill(false);

    this.setState({ open2: open2.fill(true, i, i + 1) });
  }

  render() {
    return (
      <div>
        <Menu
          key="0"
          title="one"
          open={this.state.open[0]}
          onClick={() => this.toggleDropDown(0)}
        >
          <Menu
            key="2"
            title="Alpha"
            open={this.state.open2[0]}
            onClick={() => this.toggleDropDown2(0)}
          >
            <ul>
              <li>Hello</li>
              <li>World</li>
            </ul>
          </Menu>
          <Menu
            key="3"
            title="Beta"
            open={this.state.open2[1]}
            onClick={() => this.toggleDropDown2(1)}
          >
            <ul>
              <li>Hello</li>
              <li>World</li>
            </ul>
          </Menu>
        </Menu>
        <Menu
          key="1"
          title="two"
          open={this.state.open[1]}
          onClick={() => this.toggleDropDown(1)}
        >
          <ul>
            <li>Alpha</li>
            <li>Beta</li>
          </ul>
        </Menu>
        <ul className="menu">
          <li>three</li>
          <li>four</li>
        </ul>
      </div>
    );
  }
}

ReactDOM.render(<Hello name="World" />, document.getElementById("container"));
0
Hong L 3 lipiec 2018, 21:18