【问题标题】:React update parent component when child changes the Context当孩子更改上下文时反应更新父组件
【发布时间】:2016-06-24 15:18:11
【问题描述】:

我有四个 React 组件:

  • 整体父母(App 或类似)
  • Header 孩子,由App 调用
  • Profile 页面
  • LogoutLink,由Profile 调用

我正在使用Auth0 实现用户身份验证/登录系统。当用户登录时(通过Header 中的登录按钮),App 更改User 对象的Context 以包含从Auth0 检索到的所有数据。然后,系统的任何需要它的部分都可以访问此用户数据。

登录后,UI 会自动更新(使用 Context 更改),因此 Header 现在显示“嘿,{name}”而不是之前的“登录”。这也是一个指向 Profile 页面/组件的链接(使用 React Router 的 <Link to="/profile></Link> 元素)。

Profile 页面上有一个LogoutLink。单击时,这会将用户注销,然后返回主页。它还应该自动更新 UI 以将 Header 中的消息从“Hey there {name}”改回“Login”。这是通过Context 再次更改来完成的。然而,这个功能实际上并没有起作用——用户成功退出,但要看到上面描述的变化,用户需要刷新整个页面。 this.context.user 没有更新并发送回ProfileHeader 我知道这是因为 Redux,它是单向数据流(即数据只能向下,不能向上),但我需要找到解决方法。

这是我的基本代码:

LogoutLink.js

export default class LogoutLink extends React.Component {

  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
    this.state = {
      user: null,
    };
  }

  static propTypes = {
    value: React.PropTypes.string,
  }

  static contextTypes = {
    user: React.PropTypes.object,
  } // get context so this.context is available to get initial user data (before logout)

  static childContextTypes = {
    user: React.PropTypes.object,
  }

  getChildContext() {
    return {user: this.state.user}
  } // these two are for updating context

  componentWillMount() {
    this.setState({ user: this.context.user });
  } // set the internal LogoutLink state

  onClick() {
    this.setState({ user: null }); // set the internal user state to null following logout
  }

  renderLogoutLink() {
    const {value} = this.props;
    const {user} = this.state;
    if (user != null) {
      return <Link to="/profile" onClick={this.onClick}>{value}</Link>
    } else {
      return <span>You're already logged out!</span>
    }
  }

  render() {
    return <span>{this.renderLogoutLink()}</span>
  }

}

Header.js:

export default class Header extends React.Component { // eslint-disable-line react/prefer-stateless-function
  constructor(props) {
    super(props);
    this.showLock = this.showLock.bind(this); // lock is the Auth0 module responsible for Login, also passed down by context
  }

  static contextTypes = {
    user: React.PropTypes.object,
    lock: React.PropTypes.object,
  }

  showLock() {
    const {lock} = this.context;
    lock.show();
  }

  shouldComponentUpdate(nextProps, nextState, nextContext) {
    if (this.context.user == null && nextContext.user != null) {
      return true;
    } else if (this.context.user != null && nextContext.user == null) {
      return true;
    }
    return false;
  } // after the LogoutLink is clicked, this still returns false

  renderLoginButton() {
    const {user} = this.context;
    if (user) {
      const name = user.nickname;
      return <Link to="/profile">Hey there {name}!</Link>
    } else {
      return <button onClick={this.showLock}>Login</button>
    }
  }

  render() {
    return (
      <header>
        {this.renderLoginButton()}
      </header>
    );
  }
}

我正在关注有关 Context 的官方 React 文档并对其进行更新,可在此处找到:https://facebook.github.io/react/docs/context.html

正如我所说,我知道为什么这不起作用:数据只能以一种方式发送。但我需要找到一种方法来完成这项工作,老实说,我认为我已经盯着这个太久了,现在没有选择,我的大脑有点疲惫。

【问题讨论】:

  • header shouldComponentUpdate 中 nextContext 的值是什么,应该是更新的 shouldComponentUpdate 可能是这里的罪魁祸首。请检查 nextContext.user
  • 嗨 Piyush - nextContext.user 等于 this.context.user int Header 组件 shouldComponentUpdate - 当 LogoutLink 更改上下文时它不会改变。

标签: javascript reactjs redux


【解决方案1】:

找到了解决此问题的方法。在为 User 项设置初始上下文的 App.js 代码中,我在 User 上添加了一个方法来将 User 设置为 null,然后通过应用程序向下渗透。在注销链接中,它调用此方法。代码如下:

App.js:

profile.logout = () => {
  this.setState({ profile: null });
}

getChildContext() 方法然后根据此状态更改设置用户上下文:

getChildContext() {
  return {
    user: this.state.profile
  };
}

LogoutLink.js:

onClick() {
  const {user} = this.context;
  user.logout(); 
}

【讨论】:

    【解决方案2】:

    React 的“上下文”功能很有用,但也很复杂和古怪,这就是为什么在使用它时仍有许多注意事项。特别是,我相信如果上下文内容发生变化,从shouldComponentUpdate 返回false 的组件将导致较低的组件不更新。

    我的建议是尽可能少地使用上下文,并且仅用于改变的数据。将更改的数据(例如当前用户)放入您的 Redux xtate。

    【讨论】:

    • 谢谢马克。虽然您说错误的shouldComponentUpdate 将导致较低的组件不更新,但我有相反的问题:我希望在上下文被较低的组件更改时更新较高的组件。我认为在某种程度上(根据 Redux)这是有道理的,因为数据应该只向下流动。但这也很烦人,因为理论上应该是应用程序范围内的上下文。
    • 我对上下文的理解诚然还是很模糊的,所以不要把这当成福音。也就是说,我不认为这就是上下文的工作方式。据我了解,上下文的目的是让祖先为请求它的任何后代提供一些基本不变的数据。它不是“应用程序范围内的”,除非它是您的顶级组件正在暴露的东西。这也不是后代与祖先交流的一种方式。
    猜你喜欢
    • 2018-04-22
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    • 2021-07-07
    • 2017-05-05
    • 1970-01-01
    • 2018-09-06
    • 2019-12-04
    相关资源
    最近更新 更多