Как динамически установитьState () между Родителем и Дочерним Компонентом [Logi c, запускаемый на дочернем элементе и состоянии на Root уровне приложения] - PullRequest
1 голос
/ 24 января 2020

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

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

У меня есть child компонент, который имеет <h1> tag. Этот тег возвращает сообщение, которое я отображаю динамически, как будет показано ниже.

Приложение root контейнер

У меня есть state для этого container и я хочу оставить его здесь.

Состояние:

Объектом обсуждения здесь является cockpitAlert object.

 state = {
        state = {
    persons: [
      { id: "a", name: "foo1" },
      { id: "b", name: "foo2" },
      { id: "c", name: "foo3" }
    ],
    CockpitAlert: {
      regular: "Some message",
      alert1: "The array is ending",
      alert2: "There is nothing to show"
    }
  };

Ниже показано, как я удаляю визуализированные элементы - все еще в приложении. js

personDeleteHandler = index => {
    const person = [...this.state.persons];
    person.splice(index, 1);
    this.setState({ persons: person });
  };

Ниже показано, где я отображаю свои JSX

render() {
    return (
      <div className="App">
        <Cockpit
          regular={this.state.CockpitAlert.regular}
          alert1={this.state.CockpitAlert.alert1}
          alert2={this.state.CockpitAlert.alert2}
          personsLength={this.state.persons.length}
        />
        <Person click={this.personDeleteHandler} persons={this.state.persons} />
      </div>
    );
  }

Детская кабина

Ниже находится лог c. let message динамически изменяет props в соответствии с длиной persons array, которая сокращается при щелчках.

import React from "react";

function Cockpit(props) {
  let message = props.regular;
  if (props.personsLength <= 2) {
    message = props.alert1;
  }
  if (props.personsLength === 0) {
    message = props.alert2;
  }

  return (
    <div>
      <h1>{message}</h1>
    </div>
  );
}

export default Cockpit;

Как видите, это выглядит не очень красиво.

Я не хочу, чтобы все эти разные props указывались на моей логике c:

regular={this.state.CockpitAlert.regular}
alert1={this.state.CockpitAlert.alert1}
alert2={this.state.CockpitAlert.alert2}
personsLength={this.state.persons.length}

Интересно, есть ли способ, которым я мог бы пройти просто один props, например props.message и изменить его динамически, возможно, через setState() на уровне root, где установлен state без необходимости перемещать мои логики c с Cockpit на App.js

Ответы [ 2 ]

1 голос
/ 24 января 2020

Вы можете передать функцию дочернему компоненту. Когда сообщение определено, оно вызывает функцию с сообщением в параметре. Затем родитель получает сообщение через функцию.

// Example class component
class Parent extends React.Component {
  state = {
    message: ""
  }
  
  updateMessage = message => {
    this.setState({
      message: message
    });
  }
  
  render() {
    return (
      <div>
        <div><b>This is my parent</b></div>
        <Child
          usersLength={0}
          alert1="Alert1"
          alert2="Alert2"
          alert3="Alert3"
          updateMessage={this.updateMessage}
        >
        </Child>
        <Child
          usersLength={1}
          alert1="Alert1"
          alert2="Alert2"
          alert3="Alert3"
          updateMessage={this.updateMessage}
        >
        </Child>
         <Child
          usersLength={2}
          alert1="Alert1"
          alert2="Alert2"
          alert3="Alert3"
          updateMessage={this.updateMessage}
        >
        </Child>
      </div>
    );
  }
}

class Child extends React.Component {
  constructor(props) {
    super(props);
    const {usersLength, alert1, alert2, alert3} = props;
    let message = "";
    if(usersLength <= 2) 
      message = alert1;
    if(usersLength <= 1)
      message = alert2;
    if(usersLength === 0)
      message = alert3;
    this.state = {
      message : message
    }
    props.updateMessage(message);
  }

  render() {
    const {message} = this.state;
    return <p>My child message is : {message}</p>
  }
}

// Render it
ReactDOM.render(
  <Parent />,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>
0 голосов
/ 25 января 2020

Ну, я обнаружил, как решить эту проблему, используя React Context API

, вот обновленный CodeSandBox

Сначала я создал файл auth-context.js в порядке передать мое состояние из компонента Parent в компонент child.

Поскольку logi c уже основан на Cockpit.js, я только передам свои state через React Context ApI в это дело.

auth-context.js файл

import React from 'react'

const authContext = React.createContext({
  persons: [
    { id: "a", name: "foo1" },
    { id: "b", name: "foo2" },
    { id: "c", name: "foo3" }
  ],
  message: "Some message",

});

export default authContext

В моем приложении. js контейнер

Теперь я установили Provider в App.js root контейнере:

//first of all, import the file into the root element which will Provide the //initial state on this API

import AuthContext from "./Context/auth-context";

...

class App extends Component {
  state = {
    persons: [
      { id: "a", name: "foo1" },
      { id: "b", name: "foo2" },
      { id: "c", name: "foo3" }
    ],
    CockpitAlert: {
      message: "Some message"
    }
  };

  personDeleteHandler = index => {
    const person = [...this.state.persons];
    person.splice(index, 1);
    this.setState({ persons: person });
  };

  render() {
    return (
      <div className="App">
        //I am wrapping the whole deal here and set my state so I can manage it at
        // the Cockpit.js file further on
        <AuthContext.Provider
          value={{
            persons: this.state.persons,
            message: this.state.CockpitAlert.message
          }}
        >
         //no more props being passed at Cockpit.js!!!
          <Cockpit />
          <Person
            click={this.personDeleteHandler}
            persons={this.state.persons}
          />
        </AuthContext.Provider>
      </div>
    );
  }
}

export default App;

Теперь я передам state в дочерний компонент

Cockpit.js файл

import React, { useContext } from "react";
//must import AuthContent here as well.
import AuthContext from "../../Context/auth-context";

function Cockpit(props) {
  //this is the way of setting it up on a functional component
  // now I have access to the state through authContext
  const authContext = useContext(AuthContext);

  //here I will point my state into different messages
  if (authContext.persons.length <= 2) {
    authContext.message = "running out";
  }
  if (authContext.persons.length === 0) {
    authContext.message = "nothing else to render";
  }
  //as you can see there are no props created
  return <div>{<h1>{authContext.message}</h1>}</div>;
}

export default Cockpit;

Теперь мое отражение:

Это не изменяет исходное состояние, в App.js. Будет ли это хорошей практикой в ​​этом случае?

Что вы, ребята, думаете?

...