阅读around,我发现在getInitialState()/构造函数中从props初始化状态可以是反模式。
从道具初始化状态并设法保持一致的最佳方法是什么?
正如您在下面看到的,我正在尝试初始化我的"卡"组件,以便我可以初始化 likeCount 和 isLikedByMe 状态。我这样做是因为我可以通过重置状态来显示类似于计数器的显示和要更改的Like按钮的文本。
此时,我在构造函数中执行此操作,但这是错误的方法。我应该怎么做呢?
import * as React from "react";
import { CardLikeButton } from "./buttons";
export enum CardType {
None = 0,
Text,
Image
}
export interface CardMedia {
text?: string;
imageUrl?: string;
}
export interface CardDetails {
isLikedByMe: boolean;
likeCount: number;
}
export interface CardParams extends React.Props<any> {
cardType: number;
cardId: string;
cardMedia: CardMedia;
cardDetails: CardDetails;
}
export class Card extends React.Component<CardParams, CardDetails> {
state: CardDetails;
constructor(props: CardParams) {
super(props);
console.log("in card constructor");
console.log("card type: " + props.cardType);
this.state = { // setting state from props in getInitialState is not good practice
isLikedByMe: props.cardDetails.isLikedByMe,
likeCount: props.cardDetails.likeCount
};
}
componentWillReceiveProps(nextProps: CardParams) {
this.setState({
isLikedByMe: nextProps.cardDetails.isLikedByMe,
likeCount: nextProps.cardDetails.likeCount
});
}
render() {
console.log("RENDERING CARD");
// console.dir(this.props.cardDetails);
// console.dir(this.props.cardMedia);
// console.dir(this.props.cardType);
if (this.props.cardType === CardType.Text) { // status card
return (
<div className="general-card">
<p>Text card.ID: {this.props.cardId}</p>
<p>{this.props.cardMedia.text}</p>
<CardLikeButton onButClick={this.likeButtonClicked} buttonText={this.state.isLikedByMe ? "Liked" : "Like"} isPressed={this.state.isLikedByMe}/>
<p>Like count: {this.state.likeCount}</p>
</div>
);
} else { //photo card
return (
<div className="general-card">
<p>Image card.ID: {this.props.cardId}</p>
<p> {this.props.cardMedia.text} </p>
<img src={this.props.cardMedia.imageUrl} />
<br/>
<CardLikeButton onButClick={this.likeButtonClicked} buttonText={this.state.isLikedByMe ? "Liked" : "Like"} isPressed={this.state.isLikedByMe}/>
<p>Like count: {this.state.likeCount}</p>
</div>
);
}
}
likeButtonClicked = () => {
console.log('in card => like button clicked!');
var _isLikedByMe = this.state.isLikedByMe;
var _likeCount = this.state.likeCount;
if (_isLikedByMe) {
_likeCount--;
} else {
_likeCount++;
}
_isLikedByMe = !_isLikedByMe;
this.setState({
isLikedByMe: _isLikedByMe,
likeCount: _likeCount
})
}
}
这是主要的列表组件:
/// <reference path="../../typings/index.d.ts" />
import * as React from "react";
import * as ReactDOM from "react-dom";
import {Card} from "./card";
import {CardParams, CardType, CardMedia, CardDetails} from "./card";
var card1: CardParams = {
cardType: CardType.Image,
cardId: "card1234",
cardDetails: {
isLikedByMe: false,
likeCount: 3
},
cardMedia: {
text: "some test text; badescuga",
imageUrl: "http://www9.gsp.ro/usr/thumbs/thumb_924_x_600/2016/06/19/738742-rkx1568-lucian-sinmartean.jpg"
}
};
var card2: CardParams = {
cardId: "card35335",
cardType: CardType.Text,
cardDetails: {
isLikedByMe: true,
likeCount: 1
},
cardMedia: {
text: "some test 2 text"
}
};
var cards = [card1, card2];
ReactDOM.render(
<div>
{
cards.map((item) => {
return (
<Card key={item.cardId} cardId={item.cardId} cardType={item.cardType} cardDetails={item.cardDetails} cardMedia={item.cardMedia}/>
);
})
}
</div>,
document.getElementById("mainContainer")
);
答案 0 :(得分:1)
无需与Flux或Redux合作,并专注于您的问题。
恕我直言,州和道具需要分开,其中Card
只获得道具,州从上方管理。单击like按钮后,Card
组件将获得一个事件处理程序。你可以做&#34;喜欢&#34; Card
组件中的逻辑,只是用该逻辑的输出引发事件处理程序,例如:
this.props.likeClicked(isLikedByMe, updatedLikeCount)
。
或者,在父组件中执行整个逻辑。
我还会将所有卡片包装在另一个组件中。
示例:
class Card extends React.Component {
constructor(props: CardParams) {
super(props);
}
render() {
return (
<div>
<button onClick={this.likeButtonClicked}>
{this.props.isLikedByMe ? 'Unlike' : 'Like'}
</button>
<p>Like count: {this.props.likeCount}</p>
</div>
)
}
likeButtonClicked = () => {
console.log('in card => like button clicked!');
var _isLikedByMe = this.props.isLikedByMe;
var _likeCount = this.props.likeCount;
if (_isLikedByMe) {
_likeCount--;
} else {
_likeCount++;
}
_isLikedByMe = !_isLikedByMe;
if (this.props.likeUpdated) {
this.props.likeUpdated({
cardId: this.props.cardId,
isLikedByMe: _isLikedByMe,
likeCount: _likeCount
})
}
}
}
class CardList extends React.Component {
constructor(props) {
super(props)
this.state = {
// Could use es6 map
cards: {123: {isLikedByMe: false, likeCount: 3},
124: {isLikedByMe: true, likeCount: 2}}
}
}
_onLikeUpdated({cardId, isLikedByMe, likeCount}) {
const cards = Object.assign({}, this.state.cards)
cards[cardId] = {isLikedByMe, likeCount}
this.setState({cards})
}
_getCards() {
return Object.keys(this.state.cards).map(cardId => {
return <Card key={cardId}
cardId={cardId}
likeUpdated={this._onLikeUpdated.bind(this)}
{...this.state.cards[cardId]} />
})
}
render() {
return <div>
{this._getCards()}
</div>
}
}