javascript - 我应该如何从 props 实例化我的状态?

标签 javascript reactjs typescript

阅读around ,我发现从 getInitialState()/构造函数中的 props 初始化状态可能是一种反模式。

从 props 初始化状态并保持一致的最佳方法是什么?

正如您在下面看到的,我正在尝试初始化我的“Card”组件,以便初始化 likeCountisLikedByMe 状态。我这样做是为了通过重置状态来显示自定义的“点赞”计数器,并更改“点赞”按钮的文本。

此时,我在构造函数中执行此操作,但这是错误的方法。我应该如何处理这个问题?

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")
);

最佳答案

没有开始使用 Flux 或 Redux,也没有专注于你的问题。

恕我直言,状态和 Prop 需要分开,其中 Card 仅获取 Prop ,状态由上面管理。单击“赞”按钮后,Card 组件将获取一个事件处理程序来引发。您可以在 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>
  }
}

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

关于javascript - 我应该如何从 props 实例化我的状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37922148/

相关文章:

div 上的 javascript-CSS 悬停问题

javascript - 无法裁剪图像,错误为 : failed to compile fragment shader Tensorflow. js

typescript - 使通用类型 Array<keyof T> 需要 T 的所有键

reactjs - 计算两个后续 Redux 状态之间的差异

javascript - useEffect deps 中的 ref.current 在预期时不起作用(与 useCallback ref 相比)

node.js - typescript :按值或按引用传递

javascript - 无法将数据 '19-10-2002' 转换为日期

javascript - 如何在从 typescript 生成的javascript中维护空格

javascript - 生成唯一 ID 的纯函数式方法

Javascript 对象无法访问其属性