【发布时间】:2016-04-19 16:54:41
【问题描述】:
我的任务是为客户构建一个项目,该项目需要一个父组件包装三个子组件。具体来说,父组件按照如下方式渲染子组件:
父级 = 上层 + 中层 + 下层
PARENT 组件代表一组项目中的一个。
在 TOP 组件中有一个菜单按钮,显示组中所有项目的列表,其意图是如果用户单击其中一个链接,将显示所选项目(父级将“重新渲染到”新项目 - PARENT 中的逻辑将导致出现选定的第二个项目而不是第一个)。
我在这里说得松散,如果我在说什么不清楚,可以提供代码(我认为应该是)。
我遇到的主要问题是尝试从其中一个子组件“重新渲染”父组件。本质上,有一个显示相关项目列表的菜单按钮。单击这些项目之一应重新渲染父组件,但这次显示所选项目。但是,我不知道如何做到这一点,并希望得到一些建议或帮助。我花了一上午的时间研究这个主题并尝试了一些建议的方法,但无济于事。
也许我到目前为止所采取的方法并不是完成此类任务的最佳方法。无论如何,任何帮助都会非常有帮助。谢谢!
编辑:现在工作
编辑#2:由于这已经获得了相当多的意见,我只是想澄清这是一个概念证明,也是非常简化的原型/早期版本(没有花哨的编译等 - 这个想法是否可行事情......因为我们当时不确定)。自从我从事类似的工作已经有一段时间了,但我真的很感谢所有帮助我提出这样一个令人困惑的问题,以及当时一项非常有趣和具有挑战性的任务。
import React from 'react';
import CardHeader from 'components/CardHeader';
import CardContent from 'components/CardContent';
import CardFooter from 'components/CardFooter';
module.exports = React.createClass({
getInitialState: function () {
return {
fullData: '',
//Core Card
userId: '',
cardStack: '',
cardId: '',
//Load Card
loadCard: '1',
//Optional Fields
name: '',
type: '',
headline: '',
subtitle: '',
ctext: '',
imageUrl: '',
price: '',
mapCoordinates: '',
logoUrl: '',
order: '',
email: '',
sponsorUrl: '',
pollId: '',
socialButton: ''
};
}
,
componentWillMount: function () {
//fetches cardStack and card API JSON
/** JSON Structure:
[
cardStack: ...,
cards: ...
]
**/
var fetch = function (userId, cardStackId) {
//AJAX
var json = {
'cardStack': {'id': '1', 'name': 'Test Card Stack', 'userID': 'O1AB0001'},
'cards': [{
'id': '1',
'name': 'Test Card 1',
'cardStack': '1',
'meta': 'meta_note',
'socialButton': 'twitter',
'sponsorUrl': 'https://iwantmyname.com/images/logo-url-shortener-droplr.png',
'order': 1,
'logoUrl': 'https://iwantmyname.com/images/logo-url-shortener-droplr.png',
'product': {
'headline': 'Headline Test',
'subtitle': 'Subtitle Test',
'ctext': 'Hello!!!!',
'imageUrl': 'http://the-mpas.com/wp-content/uploads/2012/04/Image-pic-54-copy.jpg',
'price': '20.00'
}
}, {
'id': '2',
'name': 'Test Card 2',
'cardStack': '1',
'meta': 'meta_note',
'socialButton': 'twitter',
'sponsorUrl': 'https://iwantmyname.com/images/logo-url-shortener-droplr.png',
'order': 2,
'logoUrl': 'https://iwantmyname.com/images/logo-url-shortener-droplr.png',
'product': {
'headline': 'Headline Test 2',
'subtitle': 'Subtitle Test 2',
'ctext': 'Hello 2!!!!',
'imageUrl': 'http://the-mpas.com/wp-content/uploads/2012/04/Image-pic-54-copy.jpg',
'price': '30.00'
}
}]
};
return json;
};
var that = this;
var getCard = function (cardArray, cardOrder) {
var card;
for (var key in cardArray) {
if (cardArray[key].order == cardOrder) {
card = cardArray[key];
}
}
if ('product' in card) {
that.setState({
type: 'product',
headline: card.product.headline,
subtitle: card.product.subtitle,
ctext: card.product.ctext,
imageUrl: card.product.imageUrl,
price: card.product.price
})
}
if ('article' in card) {
that.setState({
type: 'article',
headline: card.article.headline,
ctext: card.article.ctext
})
}
if ('map' in card) {
that.setState({
type: 'map',
mapCoordinates: card.map.mapCoordinates
})
}
if ('relatedvideo' in card) {
that.setState({
type: 'relatedvideo',
headline: card.relatedvideo.headline,
ctext: card.relatedvideo.ctext,
imageUrl: card.relatedvideo.imageUrl
})
}
if ('poll' in card) {
that.setState({
type: 'poll',
headline: card.poll.headline,
subtitle: card.poll.subtitle,
pollId: card.poll.pollId
})
}
if ('imagegallery' in card) {
that.setState({
type: 'imagegallery',
headline: card.imagegallery.headline,
ctext: card.imagegallery.ctext,
imageUrl: card.imagegallery.imageUrl
})
}
if ('profile' in card) {
that.setState({
type: 'profile',
headline: card.profile.headline,
ctext: card.profile.ctext,
imageUrl: card.profile.imageUrl
})
}
if ('newsletter' in card) {
that.setState({
type: 'newsletter',
email: card.newsletter.email
})
}
return card;
};
//Entry Point HERE
var userId = 'O1AB0001', cardStackId = 1;
var json = fetch(userId, cardStackId);
var myCard = getCard(json.cards, this.state.loadCard);
//Set core data
this.setState({
//fulldata
fullData: json,
//card stack
userId: json.cardStack.name,
cardStack: json.cardStack.id,
//card
cardId: myCard.id,
socialButton: myCard.socialButton,
order: myCard.order,
sponsorUrl: myCard.sponsorUrl,
logoUrl: myCard.logoUrl,
meta: myCard.meta,
name: myCard.name
});
},
setNew: function (nextState) {
var nsFullData = nextState.fullData;
var nsCards = nsFullData.cards;
var nsCardStack = nsFullData.cardStack;
var that = this;
var getCard = function (cardArray, cardOrder) {
var card;
for (var key in cardArray) {
if (cardArray[key].order == cardOrder) {
card = cardArray[key];
}
}
if ('product' in card) {
that.setState({
type: 'product',
headline: card.product.headline,
subtitle: card.product.subtitle,
ctext: card.product.ctext,
imageUrl: card.product.imageUrl,
price: card.product.price
})
}
if ('article' in card) {
that.setState({
type: 'article',
headline: card.article.headline,
ctext: card.article.ctext
})
}
if ('map' in card) {
that.setState({
type: 'map',
mapCoordinates: card.map.mapCoordinates
})
}
if ('relatedvideo' in card) {
that.setState({
type: 'relatedvideo',
headline: card.relatedvideo.headline,
ctext: card.relatedvideo.ctext,
imageUrl: card.relatedvideo.imageUrl
})
}
if ('poll' in card) {
that.setState({
type: 'poll',
headline: card.poll.headline,
subtitle: card.poll.subtitle,
pollId: card.poll.pollId
})
}
if ('imagegallery' in card) {
that.setState({
type: 'imagegallery',
headline: card.imagegallery.headline,
ctext: card.imagegallery.ctext,
imageUrl: card.imagegallery.imageUrl
})
}
if ('profile' in card) {
that.setState({
type: 'profile',
headline: card.profile.headline,
ctext: card.profile.ctext,
imageUrl: card.profile.imageUrl
})
}
if ('newsletter' in card) {
that.setState({
type: 'newsletter',
email: card.newsletter.email
})
}
return card;
};
var myCard = getCard(nsCards, this.state.loadCard);
this.setState({
//fulldata
fullData: nsFullData,
//card stack
userId: nsCardStack.name,
cardStack: nsCardStack.id,
//card
cardId: myCard.id,
socialButton: myCard.socialButton,
order: myCard.order,
sponsorUrl: myCard.sponsorUrl,
logoUrl: myCard.logoUrl,
meta: myCard.meta,
name: myCard.name
});
},
componentWillUpdate: function (nextProps, nextState) {
if (nextState.loadCard !== this.state.loadCard) {
this.setNew(nextState);
}
},
render: function () {
return (
<div className='sg-cardBase'>
<div className='sg-cardHeaderSection'>
<CardHeader setLoadCard={i => this.setState({loadCard: i})} data={this.state}/>
</div>
<div className='sg-cardContentSection'>
<CardContent data={this.state}/>
</div>
<div className='sg-cardFooterSection'>
<CardFooter data={this.state}/>
</div>
</div>
);
}
});
【问题讨论】:
-
请看上面编辑过的评论。主要问题是当状态改变时 Base 根本不会重新渲染。文档facebook.github.io/react/docs/component-specs.html 说不要在 ComponentWillUpdate 中设置状态...
-
我遇到的主要障碍是,点击我的菜单项后,我收到“'this' is undefined”
标签: reactjs