React js zmienia stan komponentu potomnego z komponentu rodzica

100

Mam dwa komponenty: Komponent nadrzędny, z którego chcę zmienić stan komponentu podrzędnego:

class ParentComponent extends Component {
  toggleChildMenu() {
    ?????????
  }
  render() {
    return (
      <div>
        <button onClick={toggleChildMenu.bind(this)}>
          Toggle Menu from Parent
        </button>
        <ChildComponent />
      </div>
    );
  }
}

I składnik podrzędny :

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

  toggleMenu() {
    this.setState({
      open: !this.state.open
    });
  }

  render() {
    return (
      <Drawer open={this.state.open}/>
    );
  }
}

Muszę albo zmienić stan otwarcia składnika podrzędnego ze składnika nadrzędnego, albo wywołać toggleMenu () składnika podrzędnego w składniku nadrzędnym po kliknięciu przycisku w składniku nadrzędnym?

torayeff
źródło
Może możesz mieć odniesienie do dziecka w rodzicu i wyraźnie zmienić stan dziecka, Zobacz ten dokument
Chaojun Zhong

Odpowiedzi:

125

Stan powinien być zarządzany w komponencie nadrzędnym. Możesz przenieść openwartość do komponentu podrzędnego, dodając właściwość.

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

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

   toggleChildMenu() {
      this.setState(state => ({
        open: !state.open
      }));
   }

   render() {
      return (
         <div>
           <button onClick={this.toggleChildMenu}>
              Toggle Menu from Parent
           </button>
           <ChildComponent open={this.state.open} />
         </div>
       );
    }
}

class ChildComponent extends Component {
    render() {
      return (
         <Drawer open={this.props.open}/>
      );
    }
}
Olivier Boissé
źródło
Czy można tego użyć do kontrolowania właściwości CSS, takiej jak „display”? tak jak w przypadku, jeśli mój atrybut „open” zawiera „none” lub „inline-block”, czy właściwość wyświetlania css zostanie zaktualizowana?
deusofnull
3
Tak, to jest zasadniczo to, co robi pakiet react-classnames, ale pozwala też zawsze zastosować zestaw nazw klas i warunkowo zastosować inne. Na przykład: classNames({ foo: true, bar: this.props.open });// => 'foo', gdy this.props.open = false i 'foo bar', gdy this.props.open = true.
deusofnull
1
Jak możemy zmienić stan otwarty w komponencie potomnym?
Priyabrata Atha
1
możesz dodać właściwość toggledo ChildComponent <ChildComponent open={this.state.open} toggle={this.toggleChildMenu.bind(this)} />i wywołać this.props.toggle()komponent podrzędny
Olivier Boissé
1
Nie rozumiem, możesz to wywołać w dowolnym miejscu w komponencie podrzędnym, gdy tylko określisz tę właściwość podczas deklarowania ChildComponent-><ChildComponent toggle={this.toggleChildMenu.bind(this)} />
Olivier Boissé
25

Komponent nadrzędny może zarządzać stanem potomnym, przekazując właściwość dziecku, a dziecko konwertuje tę właściwość w stanie za pomocą componentWillReceiveProps.

class ParentComponent extends Component {
  state = { drawerOpen: false }
  toggleChildMenu = () => {
    this.setState({ drawerOpen: !this.state.drawerOpen })
  }
  render() {
    return (
      <div>
        <button onClick={this.toggleChildMenu}>Toggle Menu from Parent</button>
        <ChildComponent drawerOpen={this.state.drawerOpen} />
      </div>
    )
  }
}

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

  componentWillReceiveProps(props) {
    this.setState({ open: props.drawerOpen })
  }

  toggleMenu() {
    this.setState({
      open: !this.state.open
    })
  }

  render() {
    return <Drawer open={this.state.open} />
  }
}
miguel savignano
źródło
1
w reakcji 16 użyj getDerivedStateFromProps
Fadi Abo Msalam
1
@FadiAboMsalam Używam wersji React 16.7.0 z wersją @ Types / Reaguj 16.7.18. Przynajmniej po stronie TypeScript nie ma getDerivedStateFromProps(). Jednak odpowiedź Miguela sugerująca użycie componentWillReceiveProps(props)jest dostępna i zadziałała jak urok w moim środowisku.
Manfred
W takim przypadku, w jaki sposób zmiana stanu toggleMenu () wewnątrz składnika podrzędnego dotarłaby do elementu nadrzędnego? Wyobraź sobie, że zamykam szufladę, skąd komponent nadrzędny wiedziałby, że został zamknięty?
norman123123
20

Powyższa odpowiedź jest dla mnie częściowo poprawna, ale w moim scenariuszu chcę ustawić wartość na stan, ponieważ użyłem wartości do wyświetlenia / przełączenia modalu. Więc użyłem jak poniżej. Mam nadzieję, że to komuś pomoże.

class Child extends React.Component {
  state = {
    visible:false
  };

  handleCancel = (e) => {
      e.preventDefault();
      this.setState({ visible: false });
  };

  componentDidMount() {
    this.props.onRef(this)
  }

  componentWillUnmount() {
    this.props.onRef(undefined)
  }

  method() {
    this.setState({ visible: true });
  }

  render() {
    return (<Modal title="My title?" visible={this.state.visible} onCancel={this.handleCancel}>
      {"Content"}
    </Modal>)
  }
}

class Parent extends React.Component {
  onClick = () => {
    this.child.method() // do stuff
  }
  render() {
    return (
      <div>
        <Child onRef={ref => (this.child = ref)} />
        <button onClick={this.onClick}>Child.method()</button>
      </div>
    );
  }
}

Źródła - https://github.com/kriasoft/react-starter-kit/issues/909#issuecomment-252969542

Jaison
źródło
2
To jest to, czego chcę, ale zastanawiam się, dlaczego nie używać po prostu reagowania? patrz dokumentacja
Chaojun Zhong
Co robi rekwizyt onRef?
norman123123
2

Możesz użyć createRef, aby zmienić stan komponentu podrzędnego z komponentu nadrzędnego. Oto wszystkie kroki.

  1. Utwórz metodę zmiany stanu w komponencie podrzędnym.

    2 - Utwórz odwołanie do komponentu podrzędnego w komponencie nadrzędnym za pomocą React.createRef ().

    3 - Dołącz odwołanie do komponentu podrzędnego za pomocą ref = {}.

    4 - Wywołaj metodę komponentu potomnego za pomocą this.yor-reference.current.method.

Komponent nadrzędny


class ParentComponent extends Component {
constructor()
{
this.changeChild=React.createRef()
}
  render() {
    return (
      <div>
        <button onClick={this.changeChild.current.toggleMenu()}>
          Toggle Menu from Parent
        </button>
        <ChildComponent ref={this.changeChild} />
      </div>
    );
  }
}

Komponent podrzędny


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

  toggleMenu=() => {
    this.setState({
      open: !this.state.open
    });
  }

  render() {
    return (
      <Drawer open={this.state.open}/>
    );
  }
}



Pranay kumar
źródło
1

Możesz wysłać właściwość od rodzica i użyć jej w komponencie potomnym, aby oprzeć zmiany stanu dziecka na przesłanych zmianach właściwości i możesz sobie z tym poradzić, używając getDerivedStateFromProps w komponencie potomnym.

Juba Fourali
źródło