ReactJS:通过道具

时间:2016-07-01 00:52:37

标签: javascript reactjs react-jsx

免责声明:我看过Reactjs: how to modify child state or props from parent?并且不相信答案符合我的问题。

所以我有一个可重用的有状态会话组件,它根据状态呈现不同的DOM。我还必须能够控制从父级渲染哪些DOM。

TL; DR - 我应该如何改变父组件中的子组件状态,如果有的话,还有其他选项吗?

孩子:

export default class Conversation extends Component {
  constructor(props) {
    super(props);
    
    this.state = {
      newConversation: props.showNewConversation
    };
  }
  
  render() {
   if (!this.state.newConversation) {
    return (
      <div>Current Conversation</div>
    );
   } return (
      <div>New Conversation</div>
    );
  }
}

现在我需要在不同的地方渲染这个组件,但我需要根据父级渲染相应的DOM,即从导航栏中创建一个新的对话,然后从用户页面直接进入对话和他们一起,所以当我通过它的道具给孩子打电话时,我可以控制。

通过道具呼叫孩子并设置状态:

<Conversation
  showNewConversation={this.state.isConversationShown === true}
/>

这目前正在运作,但我被告知这在React中是一个非常糟糕的做法,我的问题实际上是为什么这被认为是不好的做法,以及什么是良好的实践解决方案。

1 个答案:

答案 0 :(得分:4)

在React中,一般的最佳做法是制作尽可能多的组件和无状态&#39;如果可能的话。通常,如果您没有加载异步数据或正在接受用户输入,则状态不是必需的。

在此示例中,主要问题如下:如果父级呈现

<Conversation newConversation={true} />

后来将其重新呈现给

<Conversation newConversation={false} />

然后孩子将无法按预期呈现,因为React将更新&#39;子对话(重新渲染)但不会再次调用构造函数。因为你只将道具转移到构造函数中的状态,所以孩子永远不会改变。

相反,大多数组件只应作为其属性的函数进行渲染。您的孩子可以适应以下情况:

export default class Conversation extends Component {
  constructor(props) {
    super(props);
  }

  render() {
   if (!this.props.newConversation) {
    return (
      <div>Current Conversation</div>
    );
   } return (
      <div>New Conversation</div>
    );
  }
}

此处,父级的更新将允许子级正确地重新渲染,因为您直接引用子级的render()函数中的props。

如果您有关于正在呈现的对话的更多数据,那么您应该将所有数据作为道具传递。即。

<Conversation conversationData={{name: 'abc', new: false}} />

然后Conversation组件可以直接在render()方法中访问道具。

如果你绝对必须改变状态,那么它应该是父母改变道具的形式:

export default class Conversation extends Component {
  constructor(props) {
    super(props);

    this.state = {
      newConversation: props.showNewConversation
    };
  }

  // Response to change
  componentWillReceiveProps(nextProps){
      this.setState({newConversation: this.props.showNewConversation});

  }

  render() {
   if (!this.state.newConversation) {
    return (
      <div>Current Conversation</div>
    );
   } return (
      <div>New Conversation</div>
    );
  }
}