реагировать на передачу реквизита от ребенка обратно к родителю

avatar
BarakOren
1 июля 2021 в 17:33
69
2
2

скажем, у нас есть 3 компонента реакции, первый будет родителем, второй будет его дочерним элементом, а третий будет дочерним элементом второго компонента. поэтому я хочу передать реквизиты из третьего обратно в первый, чтобы использовать его в функции. пример кода:

class leveOne extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            blabla: bla.
        }
    }

    consoleLogChildren = () => {
        console.log(//here lets console.log the childrens props)
    }

    render(){
       return(
           <LevelTwo propsFromLevelThree={props}/>
       )
    }
}

class leveTwo extends React.Component{
    render(){
        return(
            <LevelThree propsFromLevelThree={props}/>
       )
    }
}

class leveThree extends React.Component{
    render(){
       return(
          <h1 props={props to pass back to LevelOne}>LEVEL3</h1>
       )
    }
}

надеюсь, мой вопрос ясен /: видел много информации об этом, но мне ничего не было ясно, спасибо, ребята

Источник
Noriller
1 июля 2021 в 17:38
0

возможно, вы хотите это: reactjs.org/docs/context.html возможно это: reactjs.org/docs/forwarding-refs.html

Navid Yousefzai
1 июля 2021 в 17:43
1

лучшим способом было бы использовать глобальное управление состоянием, взглянуть на API контекста реакции или для более сложных проектов я рекомендую redux.

Stuck
1 июля 2021 в 18:03
0

Или вы можете передать функцию как реквизит и использовать ее как обратный вызов в дочерних элементах, чтобы передать что-то родителю.

sashiksu
1 июля 2021 в 18:39
0

если вы хотите пройти через многие компоненты, лучше использовать управление состоянием. Таким образом, вы можете избежать сложных компонентов.

Drew Reese
1 июля 2021 в 19:00
0

@sashiksu Состояние и реквизит - две разные вещи. Хранение реквизита в состоянии является антипаттерном. Управление состоянием также не работает для функций обратного вызова, которые хочет использовать OP.

Ответы (2)

avatar
Drew Reese
1 июля 2021 в 18:24
0

Вы можете использовать простой процесс передачи реквизита от родителя к дочернему элементу. Обратите внимание, что LevelTwo передает все реквизиты, которые были ему переданы, а затем добавляет собственные.

class LevelThree extends React.Component{
  render(){
    return(
      <div>
        <h1>LEVEL3</h1>
        <button
          type="button"
          onClick={() => this.props.consoleLogChildren(this.props)}
        >
          consoleLogChildren
        </button>
      </div>
    )
  }
}

class LevelTwo extends React.Component{
  render(){
    return(
      <LevelThree {...this.props} testProp="this is a test prop"/>
    )
  }
}

class LevelOne extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      blabla: 'bla.'
    }
  }

  consoleLogChildren = (...args) => {
    console.log(...args);
  }

  render(){
    return(
      <LevelTwo consoleLogChildren={this.consoleLogChildren}/>
    )
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <LevelOne />
  </React.StrictMode> 
  rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root" />

Но этим шаблоном можно злоупотреблять, что может привести к проблеме, известной как "Сверление свойств", когда каждый компонент между ними должен обеспечить передачу всех свойств своим дочерним элементам. Вы можете решить эту проблему с помощью Context API. позволяет указать значение в контексте, и промежуточным дочерним элементам не нужно явно передавать реквизиты, которые им не нужны.

const PropContext = React.createContext({
  consoleLogChildren: () => {}
});

const PropContextProvider = ({ children }) => {
  const consoleLogChildren = (...args) => {
    console.log(...args);
  };

  return (
    <PropContext.Provider value={{ consoleLogChildren }}>
      {children}
    </PropContext.Provider>
  );
};

class LevelThree extends React.Component {
  render() {
    return (
      <div>
        <h1>LEVEL3</h1>
        <button
          type="button"
          onClick={() => this.props.consoleLogChildren(this.props)}
        >
          consoleLogChildren
        </button>
      </div>
    );
  }
}

class LevelTwo extends React.Component {
  render() {
    return (
      <PropContext.Consumer>
        {({ consoleLogChildren }) => (
          <LevelThree
            consoleLogChildren={consoleLogChildren}
            testProp="this is a test prop"
          />
        )}
      </PropContext.Consumer>
    );
  }
}

class LevelOne extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      blabla: "bla."
    };
  }

  render() {
    return (
      <PropContextProvider>
        <LevelTwo />
      </PropContextProvider>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <LevelOne />
  </React.StrictMode> 
  rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root" />
avatar
Jakub Banaś
1 июля 2021 в 18:17
0

Я думаю, что передача функции через свойства может быть здесь самым простым решением, если вы не хотите использовать какое-либо глобальное состояние.

Эта функция установит состояние родителей. Что-то вроде этого:


class LeveOne extends React.Component{
  constructor(props){
      super(props);
      this.state = {
          blabla: 'bla'
      }
  }

  consoleLogChildren = () => {
      console.log(this.state)
  }

  setBlaBla = (bla) => this.setState({blabla: bla});

  componentDidUpdate() {
    console.log(this.state);
  }

  render(){
     return(
      <div>
        <LevelTwo propsFromLevelOne={{setBlaBla: this.setBlaBla}}/>
        <p>{this.state.blabla}</p> {/* <-- it should be rendered as "hello from level 3!" */}
      </div>
     )
  }
}

class LevelTwo extends React.Component{
  render(){
      return(
          <LevelThree propsFromLevelTwo={this.props.propsFromLevelOne}/>
     )
  }
}

class LevelThree extends React.Component{
  componentDidMount() {
    this.props.propsFromLevelTwo.setBlaBla('hello from level 3!');
  }
  render(){
     return(
        <h1 props={}>LEVEL3</h1>
     )
  }
}