Reactjs项目 - 点击切换链接时出现以下错误。
“警告:setState(...):无法在现有状态转换期间更新(例如在render
或其他组件的构造函数中)。渲染方法应该是props和state的纯函数;构造函数方 - 效果是一种反模式,但可以移到componentWillMount
。“
现在我刚刚更换了运行正常的静态标记。
这就是静态标记的样子
<p className='text--white grid__row--offset--15 footer-text'>
<Link to={urls[1]} className={`text--white footer-text ${this.props.active_language === 'de' ? activeLang : alternativeLang}`} onClick={this.changeLanguageToGerman}>DE</Link>
|
<Link to={urls[0]} className={`text--white footer-text ${this.props.active_language === 'en' ? activeLang : alternativeLang}`} onClick={this.changeLanguageToEnglish}>EN</Link>
</p>
- 动态标记看起来像这样 -
{
item.children.map(function (child, j) {
return (
<span key={j}>
<Link className={'text--white footer-text transition ' + (props.active_language === child.title.toString().toLowerCase() ? activeLang : alternativeLang)} to={urls[j]} onClick={(child.title.toString().toLowerCase() === 'en' ? changeLanguageToEnglish : changeLanguageToGerman)} >{child.title}</Link>
{j === 0 && <span className='text--white'> | </span>}
</span>
)
})
}
我已经在渲染中添加了函数,所以在带有标记的返回上方
render () {
const changeLanguageToEnglish = this.changeLanguageToEnglish()
const changeLanguageToGerman = this.changeLanguageToGerman()
所以这里有一些范围问题 - 但如果我把它留作this.function - 它可能找不到它,因为它嵌套在各种循环中?
完整的例子。
import React from 'react'
import { Link, withRouter } 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'
import linkTreeObject from '../HeaderLanding/Header.lang'
import HeartIcon from './img/HeartIcon'
import './footer.scss'
// ==================================================================================================
// ==================================================================================================
//
// this is a redux container
class Footer extends React.Component {
constructor (props) {
super(props)
this.changeLanguageToGerman = this.changeLanguageToGerman.bind(this)
this.changeLanguageToEnglish = this.changeLanguageToEnglish.bind(this)
}
// ==================================================================================================
//
// change language to German called from footer link
//
changeLanguageToGerman () {
this.props.selectLanguage('de')
}
// ==================================================================================================
//
// change language to German called from footer link
//
changeLanguageToEnglish () {
this.props.selectLanguage('en')
}
// ==================================================================================================
//
getUrl (pairUrl, currentLng, enMenu, deMenu, obj) {
for (let k in obj) {
if (!obj.hasOwnProperty(k)) continue
if (obj[k].link === pairUrl) {
if (currentLng === 'de') {
return enMenu[k].link // get en link equivlant
} else {
return deMenu[k].link // get de link equivlant
}
} else {
if (!obj[k].hasOwnProperty('children') || obj[k].children.length <= 0) continue
let ret = this.getUrl(pairUrl, currentLng, enMenu[k].children, deMenu[k].children, obj[k].children)
if (typeof ret !== 'undefined') return ret
}
}
}
// ==================================================================================================
//
getLanguagePair (currentLng, pairUrl, languageObj) {
// 'find url in json tree'
let enMenu = languageObj.langs[1].lines.menu
let deMenu = languageObj.langs[0].lines.menu
let obj = {}
// find position in tree
if (currentLng === 'de') {
obj = deMenu
} else {
obj = enMenu
}
return this.getUrl(pairUrl, currentLng, enMenu, deMenu, obj)
}
// ==================================================================================================
//
fetchFooterUrls () {
let deUrl = ''
let enUrl = ''
if (this.props.active_language === 'de') {
deUrl = this.props.location.pathname
enUrl = this.getLanguagePair(this.props.active_language, this.props.location.pathname, linkTreeObject)
if (!enUrl) {
enUrl = this.getLanguagePair(this.props.active_language, this.props.location.pathname, langObject)
}
} else {
enUrl = this.props.location.pathname
deUrl = this.getLanguagePair(this.props.active_language, this.props.location.pathname, linkTreeObject)
if (!deUrl) {
deUrl = this.getLanguagePair(this.props.active_language, this.props.location.pathname, langObject)
}
}
if (!enUrl) {
enUrl = '/en'
}
if (!deUrl) {
deUrl = '/de'
}
return [enUrl, deUrl]
}
// ==================================================================================================
//
render () {
let activeLang = 'language--active'
let alternativeLang = 'language--hover'
// take the current lang state from redux and the json lang files and sends it off to receive the appropriate language object (de/en)
const lang = getLangDetails(this.props.active_language, langObject)
const urls = this.fetchFooterUrls()
const props = this.props
const changeLanguageToEnglish = this.changeLanguageToEnglish
const changeLanguageToGerman = this.changeLanguageToGerman
console.log(urls)
// get active language, get current location -- create an array for en and de urls -- determine if current url is german or english -- find its counter part from the header.lang.json
return (
<div>
{/* ---- FOOTER LARGE ---- */}
<footer className='main-footer show-for-large-up'>
<div className='row'>
{
lang.menu.reduce((m, k, i) => {
m.push(k)
if (i === lang.menu.length - 1) {
m = [m.slice(0, 1), m.slice(1)]
}
return m
}, []).map((grouped, index) => (
<div key={index} className={index === 0 ? 'main-footer__left' : 'main-footer__right'}>
{
<div className='row grid__row--offset--30'>
{
grouped.map((item, j) =>
<div key={j} className={(index === 0 && j === 0 ? 'large-45 large-centered' : 'large-14 large-offset-5') + ' columns'}>
<h2 className={'text--uppercase footer-text ' + (index === 0 ? 'text--white' : 'text--light-blue')}>{item.title}</h2>
{
item.switch
? <p className='text--white grid__row--offset--15 footer-text'>
{
item.children.map(function (child, j) {
return (
<span key={j}>
<Link className={'text--white footer-text transition ' + (props.active_language === child.title.toString().toLowerCase() ? activeLang : alternativeLang)} to={urls[j]} onClick={(child.title.toString().toLowerCase() === 'en' ? changeLanguageToEnglish.bind(this) : changeLanguageToGerman.bind(this))} >{child.title}</Link>
{j === 0 && <span className='text--white'> | </span>}
</span>
)
})
}
</p>
: item.children.map(function (child, j) {
return (
<div key={j} className={(j === 0 ? ' grid__row--offset--15' : '')}>
<Link className={'footer-text transition ' + (index === 0 ? '' : 'text--white')} to={child.link}>{child.title}</Link>
</div>
)
})
}
<div className='vert-line--light-blue footer-bars' />
</div>
)
}
</div>
}
{index !== 0
? <div className='row grid__row--offset--30'>
<div className='large-15 large-centered columns'>
<p className='text--white text--center footer-text'>Made with
<span>
<HeartIcon />
</span> in Munich.
</p>
</div>
</div>
: ''
}
</div>
))
}
</div>
</footer>
</div>
)
}
}
// ==================================================================================================
// ==================================================================================================
//
// necessary to map state props
//
const mapStateToProps = (state) => {
return {
active_language: state.active_language
}
}
// ==================================================================================================
// ==================================================================================================
//
// anything returned from this function will end up as props on the container
//
function mapDispatchToProps (dispatch) {
// whenever selectLanaguage is called it gets send to all the reducers
// bind selectLanguage is connected to the action creator to dispatch the action to the reducer
return bindActionCreators({selectLanguage: selectLanguage}, dispatch)
}
const { string, func, object } = React.PropTypes
Footer.propTypes = {
deURL: string,
enURL: string,
selectLanguage: func,
active_language: string,
location: object
}
// this connects the container to redux
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Footer))
答案 0 :(得分:0)
以下函数似乎在渲染期间更新组件状态。你不应该调用它,因为它会更新触发该错误消息的状态。 (即改为:
render () {
const changeLanguageToEnglish = this.changeLanguageToEnglish
const changeLanguageToGerman = this.changeLanguageToGerman
如果要在没有提到this
问题的情况下将状态更新函数传递给子组件,可以使用bind或将函数定义为成员变量而不是方法。
使用bind
{
item.children.map(function (child, j) {
return (
<span key={j}>
<Link onClick={(child.title.toString().toLowerCase() === 'en' ? changeLanguageToEnglish.bind(this) : changeLanguageToGerman.bind(this))} >{child.title}</Link>
{j === 0 && <span className='text--white'> | </span>}
</span>
)
})
}
将其定义为成员变量
class SomeComponent extends React.Component {
changeLanguageToGerman = () => {
}
...
render() {
}
}