如何在父组件和子组件之间动态设置状态()

How to setState() dynamically in between Parent and Child Component [Logic being run on child & state on the Root App level]

我在学习 React 时正在闲逛,我想知道对于下面介绍的场景,什么是优雅的解决方案。

按照此 Link 查看完整的代码集。

我有一个 child 组件,它有一个 <h1> tag。此标记 returns 我正在动态显示的消息,如下所示。

应用根容器

我的 state 在这个 container 上,我想把它放在那里。

状态:

这里讨论的对象是cockpitAlertobject.

 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"
    }
  };

下面是我如何删除渲染的项目 - 仍然在 App.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>
    );
  }

座舱子

逻辑如下。 let message 根据 persons array 的长度动态更改 props,点击后会缩短。

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 都指向我的逻辑:

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 而无需将我的逻辑从 Cockpit 移动到 App.js

您可以将函数传递给子组件。定义消息后,它会调用带有消息参数的函数。 Parent 然后通过函数接收消息。

// 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>

好吧,我发现了如何使用 React Context API

解决这个问题

这是更新后的 CodeSandBox

我首先创建了文件 auth-context.js,以便将我的状态从 Parent 组件传递到 child 组件。

由于逻辑已经基于 Cockpit.js,在这种情况下,我只会通过 React Context ApI 传递我的 state

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

在我的 App.js 容器上

现在我已经在 App.js root 容器中设置了 Provider

//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 处的原始状态。在这种情况下,这是一个好的做法吗?

大家怎么看?