2016-06-20 2 views
0

Чтение around, я вижу, что инициализирующее состояние из реквизита в getInitialState()/constructor может быть анти-шаблоном.Как мне создать экземпляр моего состояния из реквизита?

Каков наилучший способ инициализации состояния от реквизита и управления, чтобы он был последовательным?

Как вы можете видеть ниже, я пытаюсь инициализировать мой компонент «карты», так что я, возможно, 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

Вы используете состояние контейнера, как Redux? – Mark

+0

Где исходный реквизит? – omerts

+0

@ Марк нет, я не! я новичок и пытаюсь найти лучшие методы работы с реагированием. Есть ли способ справиться с этим без помощи сокращений? – Alex

ответ

1

Не вдаваясь в работе с Flux или Redux, и сосредоточив внимание на ваш вопрос.

IMHO, состояние и реквизит необходимо разделить, где Card получает только реквизиты, а состояние управляется сверху. Компонент Card получит обработчик события, который нужно поднять, как только кнопка щелкнула. Вы можете либо сделать логику «как» внутри компонента 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> 
    } 
} 

Fiddle: https://jsfiddle.net/omerts/do13ez79/

Смежные вопросы