【问题标题】:reactjs resetting props for componentWillReceivePropsreactjs为componentWillReceiveProps重置道具
【发布时间】:2017-09-14 20:41:35
【问题描述】:

我的第一个 react 项目的第一个问题。

我正在尝试弄清楚如何在特定的 onClick 链接上最好地影响组件,以便能够重新触发此效果并且不使其受到页面上其他链接的影响。前两个问题有效,但我似乎无法让其他链接不影响组件。

我的页面上有一个 DisplayLightbox 组件,它接受几个值

<div>
  <DisplayLightbox 
    showLightbox = {this.state.showLightbox} 
    lightboxValue = {this.state.travelCity}  
  /> 
</div>

我要触发灯箱的链接正在调用一个设置状态(并发送道具)的函数。这部分似乎工作正常。

onClick={() => this.showLightbox(el.field_city)}

showLightbox(travelCity){
  this.setState({
    showLightbox: true,
    travelCity: travelCity,
  });
}

在我的 DisplayLightbox 组件中,componentWillReceiveProps 确实将 state 设置为 true,这会在 div 中添加 lb-active 类,该类从 css 中显示灯箱 div。这似乎很好。

class DisplayLightbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
    showLightbox: false, 
    };
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.showLightbox !== this.state.showLightbox) {
      this.setState({ showLightbox: nextProps.showLightbox });
    }
  } 

  closeLightbox() {
    this.setState({
      showLightbox: false,
    });
  }

  render() {
    var lbActive = (this.state.showLightbox === true) ? "lb-active" : "" 
    return <div className={"lightbox " + lbActive }>
    <div className={"lightbox-close " + lbActive }  onClick={() => 
  this.closeLightbox()}>CLOSE</div>
    Copy in lightbox
    </div>;
  }
}

查看它,我发现由于 props 不受组件控制并且是只读的,因此一旦将其设置为 True 并且我通过将 showLighbox 的状态设置回 false 来关闭 div,nextProps.showLightbox 仍然为 true。因此,如果我关闭它(closeLightbox)并单击页面上的另一个 onClick,它仍会查看我的组件,看到 nextProps.showLightbox 仍设置为 TRUE 并打开灯箱。

如果该特定链接是被点击的链接,我只希望打开灯箱。让所有其他链接都将 showLightbox 的状态设置为 false 似乎有点矫枉过正,所以我猜我没有正确看待这个问题。

谢谢

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    您可以将 closeLightbox 方法移动到上层组件并从父组件管理 showLightbox 属性。那么组件DisplayLightbox将有3个props:showLightboxtravelCity和方法closeLightbox

    当您将关闭灯箱移动到父组件时,应该不再需要事件componentWillReceiveProps

    【讨论】:

    • 非常感谢您的快速回复。我已经向父级添加了一个按钮 div 来切换 showLightbox 状态,正如您所说,我能够从子级中删除 componentWillReceiveProps。似乎有效。
    【解决方案2】:

    让所有其他链接都设置 showLightbox 为假,所以我猜我没看这个 正确。

    那为什么不只配置一个你想打开/关闭灯箱的链接呢?

    在我看来,从父组件或外部组件获取其活动状态的组件不应该费心在自己的状态下管理它。
    您可以在父状态下管理开/关状态,并将isOnonClose 事件处理程序传递给LightBox
    单击LightBox 后,它将调用传递给它的处理程序,并且父级将isOn 的状态更改为false,这将触发isOn 的新属性LightBox 的渲染这次它的值是false
    在单击外部link / button 时,父级将收听它并将isOn 的状态更改为true,然后isOn 将再次传递给LightBox,其闪亮的新值为@987654336 @。

    小例子:

    const cities = ["ny", "tlv", "ark"];
    
    class Button extends React.Component {
      constructor(props) {
        super(props);
        this.onClick = this.onClick.bind(this);
      }
    
      onClick() {
        const { item, onClick } = this.props;
        onClick(item);
      }
    
      render() {
        return <button onClick={this.onClick}>{this.props.children}</button>;
      }
    }
    
    class LightBox extends React.Component {
      constructor(props) {
        super(props);
        this.onClick = this.onClick.bind(this);
      }
    
      onClick() {
        const { city, onClick } = this.props;
        onClick(city);
      }
    
      render() {
        const { isOn } = this.props;
        const css = `lightBoxStyle ${isOn && "onStyle"}`;
        return (
          <div 
            className={css}
            onClick={this.onClick}>
            |
          </div>
        );
      }
    }
    
    class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          turnedOn: []
        };
    
        this.on = this.on.bind(this);
        this.off = this.off.bind(this);
      }
    
      on(city) {
        const { turnedOn } = this.state;
        if (turnedOn.find(c => c === city)) {
          return;
        }
        const nextState = [...turnedOn, city];
        this.setState({ turnedOn: nextState });
      }
    
      off(city) {
        const nextState = this.state.turnedOn.filter(c => c !== city);
        this.setState({ turnedOn: nextState });
      }
    
      render() {
        const { turnedOn } = this.state;
        return (
          <div>
            {cities.map((city, i) => {
              const isOn = turnedOn && turnedOn.includes(city);
    
              return (
                <div style={{ display: "inline-block", margin: "0 10px" }}>
                  <LightBox city={city} isOn={isOn} onClick={this.on} />
                  <hr />
                  <Button item={city} onClick={this.off}>
                    Close the light!
                  </Button>
                </div>
              );
            })}
          </div>
        );
      }
    }
    
    ReactDOM.render(<App />, document.getElementById("root"));
    .lightBoxStyle{
      border: 1px solid #eee;
      width: 30px;
      height: 30px;
      text-align: center;
      box-shadow: 0 0 4px 1px #222;
      border-radius: 50%;
      margin: 0 auto;
      cursor: pointer;
    }
    
    .onStyle{
      background-color: #333;
      color: #fff;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id="root"></div>

    【讨论】:

    • 这太棒了!我使用了您的按钮想法,尽管它是一个隐藏的 div,仅在 showLightbox 为真时显示。此外,“从父组件或外部组件获取其活动状态的组件,不应该费心以自己的状态管理它”非常有帮助。虽然,在 DisplayLightbox 类中,这将是我将功能添加到其中的地方(我相信)。
    • 确实,您可以在LightBox 中管理一个状态,但它应该是一个只关注LightBox 的状态。请记住,在Matrix电影中,“Neo”并没有决定成为被选中的人,而是外力为他决定的:)
    • @user1932694 顺便说一句,如果您认为它有帮助,您可以投票赞成答案,如果答案为您提供了解决方案,那么您应该接受它,以便将您的问题标记为已回答。
    【解决方案3】:

    根据出色的回复,我将孩子关闭并返回给父母。 我通过向父级添加一个灯箱按钮 div 来做到这一点

            <div className={"lightbox-button " + this.state.showLightbox} onClick={() => this.showLightbox()}></div>
    
           <DisplayLightbox 
           showLightbox = {this.state.showLightbox} 
          lightboxValue = {this.state.travelCity}  /> 
    

    这调用了相同的函数 showLightbox,我稍作修改以切换

      showLightbox(travelCity){
    this.setState({
      showLightbox: !this.state.showLightbox,
      travelCity: travelCity,
    });
    

    }

    使用 css,我将这个灯箱按钮隐藏起来,除非 this.state.showLightbox 为真。发生这种情况时,会显示按钮,单击时会切换 showLightbox 状态,从而移除灯箱和按钮。

    不确定这是否是理想的解决方案,但它似乎有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-05
      • 1970-01-01
      • 1970-01-01
      • 2018-07-19
      • 1970-01-01
      • 2018-04-01
      • 1970-01-01
      相关资源
      最近更新 更多