Reactjs, редукторы, переключение языка

Я только что взял на себя новый проект reactjs - и я пытаюсь просмотреть, как было вызвано переключение языка.

так что в нижнем колонтитуле есть две ссылки для переключения языка.

//footer.js

import React from 'react'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { selectLanguage, getLangDetails } from '../../actions/action_language'
import langObject from './Footer.lang'

class Footer extends React.Component {
  constructor (props) {
    super(props)
    this.changeLanguageToGerman = this.changeLanguageToGerman.bind(this)
    this.changeLanguageToEnglish = this.changeLanguageToEnglish.bind(this)
  } 

  changeLanguageToGerman () {
    this.props.selectLanguage('de')
  }

  changeLanguageToEnglish () {
    this.props.selectLanguage('en')
  } 

  render () {
    let activeLang = 'language--active'
    let alternativeLang = 'language--hover'
    const lang = getLangDetails(this.props.active_language, langObject)
    return (
      <div>
        <footer className='main-footer show-for-medium-only'>
          <div className='medium-15 columns'>
            <p className='text--white grid__row--offset--15 footer-text'>
              <Link to={this.props.deURL} className={`text--white footer-text ${this.props.active_language === 'de' ? activeLang : alternativeLang}`} onClick={this.changeLanguageToGerman}>DE</Link>
              &nbsp;&nbsp;&#124;&nbsp;&nbsp;
              <Link to={this.props.enURL} className={`text--white footer-text ${this.props.active_language === 'en' ? activeLang : alternativeLang}`} onClick={this.changeLanguageToEnglish}>EN</Link>
            </p>
          </div>
        </footer>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    active_language: state.active_language
  }
}

function mapDispatchToProps (dispatch) {
  return bindActionCreators({selectLanguage: selectLanguage}, dispatch)
}

const { string, func } = React.PropTypes
Footer.propTypes = {
  deURL: string,
  enURL: string,
  selectLanguage: func,
  active_language: string
}

export default connect(mapStateToProps, mapDispatchToProps)(Footer)

// заголовок.js

import React from 'react'
import { connect } from 'react-redux'
import { getLangDetails } from '../../actions/action_language'
import langObject from './Header.lang'

class Header extends React.Component {
  render () {
    let transparent
    transparent = this.props.transparent ? 'transparent' : ''
    const lang = getLangDetails(this.props.active_language, langObject)
    return (
      <div>
        <header className={` main_headerbar__landing transition show-for-large-up ${transparent} `}>
          <div className='contain-to-grid'>
            {lang}
          </div>
        </header>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    active_language: state.active_language
  }
}

const { bool, string } = React.PropTypes
Header.propTypes = {
  transparent: bool,
  active_language: string
}

export default connect(mapStateToProps)(Header)

--- так что это компоненты верхнего/нижнего колонтитула - и у каждого есть файл json, который разбивается на массив lang.

есть файл, который выглядит как какой-то глобальный js, который, как я думаю, подключается к этому, но я изо всех сил пытаюсь расширить эту функциональность на остальные компоненты/страницы сайта.

//action_language.js

export const LANGUAGE_SELECTED = 'LANGUAGE_SELECTED'

export function selectLanguage (language) {
  return {
    type: LANGUAGE_SELECTED,
    payload: language
  }
}

export function getLangDetails (language = 'de', langObject) {
  const langData = langObject.langs.filter((langVar) => langVar.lang === language)
  return langData['0'].lines
}

Итак, вот первая страница, называемая услугами. Теперь то, что бросает меня в первую очередь здесь, вместо того, чтобы использовать active_language, это теперь просто язык.

//services.js

import React from 'react'
import Header from '../HeaderLanding/Header'
import Footer from '../Footer/Footer'
import NoBundle from './NoBundle'
import HowTiles from './HowTiles'
import CarouselTiles from './CarouselTiles'
import YourAdvantages from './YourAdvantages'
import InformationTiles from './InformationTiles'
import ContactTiles from './ContactTiles'

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { selectLanguage, getLangDetails } from '../../actions/action_language'

// language file
import langObject from './services.lang.json'

//  services css
import './services.css'

// getting the distinct URLs from the lang files
const deURL = langObject.langs[0].pageURL
const enURL = langObject.langs[1].pageURL

const Spacers = () => (
  <div>
    <div className='row show-for-large-up' style={{ height: '250px' }} />
    <div className='row show-for-medium-only' style={{ height: '150px' }} />
    <div className='row show-for-small-only' style={{ height: '80px' }} />
  </div>
)

class Services extends React.Component {
  constructor (props) {
    super(props)
    this.language = props.match.params.langURL
  }
  componentWillMount () {
    document.getElementById('body').className = 'overlay-background-services'

    this.updateLanguage()
  }
  updateLanguage () {
    console.log('updatelang', this.language)
    if (this.language === 'de' || !this.language) {
      this.props.selectLanguage('de')
    } else {
      this.props.selectLanguage('en')
    }
  }
  componentWillUnmount () {
    document.getElementById('body').className = ''
  }

  render () {
    const lang = getLangDetails(this.language, langObject)
    return (
      <div>
        <Header transparent />
        <Spacers />
        <NoBundle lang={lang} />
        <HowTiles />
        <CarouselTiles />
        <YourAdvantages />
        <InformationTiles />
        <ContactTiles />
        <Footer deURL={deURL} enURL={enURL} />
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    language: state.language
  }
}

function mapDispatchToProps (dispatch) {
  return bindActionCreators({selectLanguage: selectLanguage}, dispatch)
}

const { func, string, object } = React.PropTypes
Services.propTypes = {
  selectLanguage: func,
  langURL: string,
  params: object,
  match: object
}

export default connect(mapStateToProps, mapDispatchToProps)(Services)

person The Old County    schedule 11.05.2017    source источник
comment
можно поконкретнее с чем вы боретесь? трудно ответить на ваш вопрос, потому что вы еще не задаете вопрос   -  person azium    schedule 12.05.2017
comment
хорошо - мне немного сложно поставить это в вопросе. По сути, у вас есть переключатель, который вызывается двумя ссылками в нижнем колонтитуле, поэтому он вызовет изменение языкового содержимого нижнего колонтитула, используя данные из файла json. -- заголовок также корректно воспринимает это изменение. -- Я полагаю, что мой первый вопрос -- это лучший способ решить эту проблему -- просто сосредоточившись на коде верхнего/нижнего колонтитула -- второй вопрос переносит эту логику в другие части сайта   -  person The Old County    schedule 12.05.2017
comment
ваш первый вопрос: ничего не зная о вашем приложении, я не знаю ... но это кажется разумным. ваш второй вопрос все еще не вопрос. может быть, попробуйте сначала сделать это где-нибудь.. может быть, это сработает, ошибка или вы застрянете, пытаясь. потом вернись и спроси   -  person azium    schedule 12.05.2017
comment
Проблема, с которой я сталкиваюсь, заключается в том, что я начинаю добавлять аналогичную логическую обработку в компонент, который обрабатывает фактическую страницу, он состоит из более мелких компонентов, он отлично работает при обновлении страницы до этого URL-адреса, но не обновляется на выключатель   -  person The Old County    schedule 12.05.2017
comment
Я думаю, что mapStateToProps в моем файле страницы - не обновляется при изменении - не так, как верхний/нижний колонтитул   -  person The Old County    schedule 12.05.2017
comment
Можете ли вы опубликовать код, который вы пытались написать? это был бы самый простой способ увидеть, что вы делаете неправильно, если что-то.   -  person azium    schedule 12.05.2017
comment
конечно - хорошо, проверьте services.js - он использует функцию updateLanguage - имеет функции componentWillMount и конструктора... - включает ли он верхний/нижний колонтитул как включение и какую-то проблему, выходящую за рамки?   -  person The Old County    schedule 12.05.2017
comment
** проблема здесь - работает ли это при обновлении страницы - но не при нажатии на ссылки внизу - как будто он просто повторно отображает service.js - без получения параметра нового языка?   -  person The Old County    schedule 12.05.2017


Ответы (1)


Компонент нижнего колонтитула устанавливает текущий язык, вызывая создателя действия Redux selectLanguage. По сути, это отправляет действие (вы можете думать об этом как о пользовательском событии с некоторыми соответствующими данными — языком) в хранилище, которое сохранит выбранный пользователем язык для использования в другом месте.

Чтобы использовать язык в других компонентах, этот выбор языка необходимо передать в компонент (в данном случае заголовок) из хранилища Redux.

Это код интереса в заголовке, который делает это...

const mapStateToProps = (state) => {
  return {
    active_language: state.active_language
  }
}

export default connect(mapStateToProps)(Header)

Здесь вы подключаете заголовок к хранилищу с помощью функции, которая описывает, как хранилище должно отображать значения в реквизиты вашего реагирующего компонента. state.active_language - это место, где хранится язык, выбранный пользователем, и это говорит о том, что он должен быть передан как реквизит с именем active_language в вашем компоненте заголовка.

Функция connect — это декоратор, который создаст то, что известно как компонент высшего порядка (HOC), который, по сути, представляет собой компонент с реквизитами или функциями, автоматически внедренными в него (в данном случае украшенный автоматически переданным значением для реквизита active_language из магазина).

Вы можете сделать то же самое для любого другого компонента, которому нужна эта настройка языка, или сделать еще один или два шага.

Вместо того, чтобы передавать имя активного языка, передайте сам соответствующий язык...

import { getLangDetails } from '../../actions/action_language'
import langObject from './Header.lang'

const mapStateToProps = (state) => {
  return {
    active_language: getLangDetails(state.active_language, langObject)
  }
}

export default connect(mapStateToProps)(Header)

ИЛИ еще лучше напишите другой HOC, который обертывает любой компонент, который вы передаете, с этой информацией...

import { getLangDetails } from '../../actions/action_language'

export default const injectLanguage = (component, langObject) => connect((state) => ({
    language: getLangDetails(state.active_language, langObject)
  })
)(component)

Затем в последующих компонентах с реквизитом language украсьте этим

import injectLanguage from './some/where'
import langObject from './MyLanguageDetailsAwareComponent.lang'

class MyLanguageDetailsAwareComponent extends React.Component {

  render() {
    return this.props.language
  }

}

export default injectLanguage(MyLanguageDetailsAwareComponent, langObject)
person alechill    schedule 12.05.2017
comment
Привет, @alechill, я обновил вопрос, чтобы показать вам проблему, с которой я переключаю язык в основной части страницы - service.js - person The Old County; 12.05.2017
comment
Похоже, что он передается через реквизиты хранилища как language и никогда не используется, а также из маршрута или чего-то, что сопоставляется, а затем сбрасывает значение хранилища на то, что было сопоставлено в маршруте при каждом обновлении компонента, полностью игнорируя и переопределяя хранилище. . Кажется, что ваш селектор страницы и нижнего колонтитула работает друг против друга, и страница выигрывает - person alechill; 12.05.2017
comment
Изменение на this.language = props.language || props.match.params.langURL предпочтет настройку хранилища, если пользователь уже установил ее, но по умолчанию будет использоваться язык, который, как я полагаю, является маршрутом при первом использовании, я думаю. Извините, я сейчас на телефоне, так что это не слишком подробно - person alechill; 12.05.2017
comment
-- это хорошие идеи - я постараюсь завтра разобраться с этим сам -- я не писал этот код, поэтому мне тоже немного сложно реконструировать -- я пытался сделать что-то вроде props.language -- но это ошибка, так как к этому моменту он доступен только для чтения. - person The Old County; 12.05.2017
comment
Я добавил ваш код в проект, но похоже, что props.language ВСЕГДА не определен --- а также при нажатии на ссылку - он никогда не вызывает конструктор снова, поэтому this.language я не думаю, что поддерживает это props.language — если честно — похоже, что props.language никогда не устанавливается? - person The Old County; 12.05.2017
comment
В конструкторе это, скорее всего, будет неопределенным, как если бы это было определение страницы, у вас еще не было возможности изменить язык. Переместите `this.updateLanguage()` в конструктор вместо willupdate и вместо этого используйте const lang = getLangDetails(this.props.language, langObject) в рендеринге. - person alechill; 12.05.2017
comment
попробовал это - похоже, this.props.language всегда не определен - person The Old County; 12.05.2017
comment
Аааа, конечно, в соответствии с нижним колонтитулом, он должен сопоставляться с state.active_language. Проверьте редукторы на наличие правильного свойства состояния для сопоставления и использования его в обоих - person alechill; 12.05.2017
comment
Я смотрел на это -- потому что он ищет state.language в этом service.js -- const mapStateToProps = (state) =› { console.log('state', state) return { language: state.language } } - person The Old County; 12.05.2017
comment
но когда я переключаюсь на active_language -- я думаю, что для него тоже установлено значение null, и поэтому он снова не может найти позицию массива по умолчанию для перехода -- потому что он не имеет никакого значения -- en или gb - person The Old County; 12.05.2017