2016-06-20 9 views
0

aroundを読むと、私はgetInitialState()/ constructorの小道具から状態を初期化するのがアンチパターンになることがわかります。私の状態を小道具からどのようにインスタンス化すればよいですか?

状態を初期化して一貫性を維持する最良の方法は何ですか?

あなたは以下を参照することができますように、私は私が初期化さlikeCountisLikedByMe状態を持つことができるように、私の「カード」コンポーネントを初期化しようとしています。私はこのようにして、カウンターのようなカウンターが表示され、状態をリセットすることによって、Likeボタンのテキストを変更することができます。

この時点で、私はコンストラクタでこれをやっていますが、これを行うには間違った方法です。私はこれをどのように管理すべきですか?フラックス、またはReduxのと協力し、あなたの質問に焦点を当てにならずに

/// <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

あなたは再来のような状態のコンテナを使用していますか? – Mark

+0

最初の小道具はどこから来ていますか? – omerts

+0

@マークノー、そうではありません!私は初心者であり、反応に取り組む際のベストプラクティスを得ようとしています。 reduxの助けなしにこれを管理する方法はありますか? – Alex

答えて

1

:ここ

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 
     }) 
    } 
} 

は、メインリストコンポーネントです。

IMHO、州と小道具は分離する必要があります。Cardは小道具を取得し、上から状態を管理します。 Cardコンポーネントは、likeボタンがクリックされると発生させるイベントハンドラを取得します。 Cardコンポーネントの中で "like"ロジックを実行し、そのロジックの出力を持つイベントハンドラを発生させるだけです(例: 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> 
    } 
} 

フィドル:https://jsfiddle.net/omerts/do13ez79/

関連する問題