Передача пользовательского состояния дочернему компоненту в React

У меня есть родительский компонент, который получает состояние пользователей (независимо от того, вошли ли они в систему или нет) и должен иметь возможность передавать это состояние дочернему компоненту и отображать ссылку в зависимости от того, вошли ли они в систему. Однако у меня есть проблемы с передачей состояния loggedIn дочернему компоненту, поэтому его можно использовать для отображения или скрытия ссылки в зависимости от состояния пользователя:

Родительский компонент

class VideoPlayer extends React.Component {
  constructor (props) {
    super(props)
    this.state = {

    }
  }

  async componentDidMount () {
    if (this.md.mobile()) {
      this.setState({ blocking: 'mobile' })
    } else if (this.browser.name === 'ie' || this.browser.name === 'edge') {
      this.setState({ blocking: 'unsupported' })
    } else {
      try {
        const userData = await superagent.get('/api/user')

        if (!userData.error) {
          this.setState({ user: userData.body })
        }
        const loggedIn = userData.body.success <==RETURNS FALSE IF USER IS LOGGED OUT AND "UNDEFINED" IF USER IS LOGGED IN
        console.log(loggedIn)
      } catch (err) {
        console.log('Could not fetch user.', err)
      }

      this.fetchData()
    }
  }

  /**
   * render
   */

  render () {
    return (
      <div className='video-player-container'>
        { this.state.blocking === 'paywall' &&
          <Paywall
            bgImgUrl={this.props.imageUrl('paywall-bg.png' )}
            logoUrl={this.props.imageUrl('logo.png')}
            loggedIn={!!this.state.user && this.state.user.success === undefined}
            {...this.props}
          />
        }
      </div>
    )
  }
}

Дочерний компонент

function Paywall (props) {
  const { iconHrefs, logoUrl, bgImgUrl, config } = props

  return (
    <div
      className='blocking-paywall'
      style={{ backgroundImage: `url(${bgImgUrl})` }}>
      <div className='container'>
        <div className='logo'>
          <img src={logoUrl} />
        </div>

        <h1 className='heading lg'>{content.heading}</h1>

        <div className='message'>
          <div className='subpara'>
            content
          </div>
          <div className='subpara'>
            catchphrase
          </div>
        </div>

        <div className='login'>
          { !props.loggedIn &&  <==SHOULD ONLY SHOW LOGIN LINK IF USER IS NOT LOGGED IN
            <p>already a member?<a href='/login'>Login</a></p>
          }
        </div>
      </div>
    </div>
  )
}

person Matt    schedule 22.05.2018    source источник


Ответы (2)


Во-первых, вы не передаете свойство loggedIn своему дочернему компоненту.

<Paywall
        bgImgUrl={this.props.imageUrl('paywall-bg.png' )}
        logoUrl={this.props.imageUrl('logo.png')}
        {/* How did you expect child component to get loggedIn?*/}
        loggedIn={!!this.state.user && this.state.user.success === undefined}
        {...this.props} 
      />

Тогда ваш Paywall является компонентом без сохранения состояния. У него нет экземпляра, вы не можете использовать this в методе рендеринга

  <div className='login'>
      { !props.loggedIn &&  <==SHOULD ONLY SHOW LOGIN LINK IF USER IS NOT LOGGED IN
        <p>already a member?<a href='/login'>Login</a></p>
      }
    </div>
person Yury Tarabanko    schedule 22.05.2018
comment
Я обновил свой код на основе вашего предложения, но ссылка по-прежнему отображается, когда пользователь вошел в систему. - person Matt; 22.05.2018
comment
@Matt Поскольку вы используете undefined как флаг this.state.user.success === undefined или "UNDEFINED"? :) Кто знает :) - person Yury Tarabanko; 22.05.2018

Вы должны передать loggedIn в качестве реквизита для платного доступа, поскольку вы не получаете его в качестве реквизита для родительского компонента, поэтому {...this.props} недостаточно.

person Bruno Mazzardo    schedule 22.05.2018