从React“截断文本”组件上的道具派生的状态

时间:2019-03-22 09:17:35

标签: reactjs

我对React还是很陌生,大约一个星期前才开始使用它。我正在尝试在组件中开发截断文本功能,并陷入了似乎是常见的新手陷阱中。

我有一个患者信息组件,该组件显示人们的个人数据,例如姓名,出生日期等。该组件在视觉上设计为宽度固定的卡片,每当其宽度超过用户姓名的宽度时,都必须将其截断卡:

Original text Truncated text

(“截断”格式非常具体,我不能仅使用CSS做到这一点)

我正在通过道具将人员的姓名和姓氏从父组件传递到子PatientName组件,该子组件封装并处理截断功能。这是我正在使用的代码:

import './patient-name.css';

import React from 'react';
import PropTypes from 'prop-types';

const TRUNCATED_MAX_SURNAME_CHARS = 10;
const TRUNCATED_SURNAME_ELLIPSIS = '...';

const TRUNCATED_MAX_NAME_CHARS = 1;
const TRUNCATED_NAME_ELLIPSIS = '.';

class PatientName extends React.Component {
  constructor(props) {
    super(props);

    this.state = { name: props.name, surname: props.surname };

    this.$element = React.createRef();
    this.$name = React.createRef();
  }

  isOverflowing() {
    const elementRightPos = this.$element.current.getBoundingClientRect().right;
    const nameRightPos = this.$name.current.getBoundingClientRect().right;

    return nameRightPos > elementRightPos;
  }

  componentDidMount() {
    if (this.isOverflowing()) this.truncate();
  }

  truncate() {
    this.setState({
      name: `${this.props.name.substring(
        0,
        TRUNCATED_MAX_NAME_CHARS,
      )}${TRUNCATED_NAME_ELLIPSIS}`,
      surname: `${this.props.surname.substring(
        0,
        TRUNCATED_MAX_SURNAME_CHARS,
      )}${TRUNCATED_SURNAME_ELLIPSIS}`,
    });
  }

  render() {
    return (
      <h4 className="patient-name" ref={this.$element}>
        <span className="patient-surname">{this.state.surname}</span>
        &nbsp;
        <span ref={this.$name}>{this.state.name}</span>
      </h4>
    );
  }
}

PatientName.propTypes = {
  name: PropTypes.string,
  surname: PropTypes.string,
};

export default PatientName;

这工作正常(我现在不担心截断性能)...直到在父组件中选择另一位患者。然后,患者姓名不会更改,它仍然显示我通过道具传递的先前姓名。

我知道问题是从props派生状态,并且构造函数仅被调用一次,状态永远不会在之后刷新,等等,但是……这样做的正确“反应方式”是什么?

我来自Angular背景,我仍在努力解决这个问题。

谢谢!

PS:我正在使用React 16.6

2 个答案:

答案 0 :(得分:0)

如果道具发生变化,您需要更新状态:

componenDidUpdate(prevProps, prevState) {
  if (prevProps.name !== this.props.name || prevProps.surname !== this.props.surname) {
    this.setState({name: this.props.name, surname: this.props.surname});
  }
  else if (prevState.name !== this.state.name || prevState.surname !== this.state.surname) {
    if (this.isOverflowing()) this.truncate();
  }
}

首先if更新状态并使用新的未截断的props重新呈现并获得新的度量。第二个if用于检查新的度量并在需要时截断。

答案 1 :(得分:0)

从React 16.3+开始,有一个新的组件生命周期,这是一个称为getDerivedStateFromProps的静态方法,它返回状态并在组件接收道具时被触发

因此在您的示例中,您可以像这样使用它:

static getDerivedStateFromProps(nextProps, state) {
   return ({
  ...state,
  name: `${nextProps.name.substring(
    0,
    TRUNCATED_MAX_NAME_CHARS,
  )}${TRUNCATED_NAME_ELLIPSIS}`,
  surname: `${nextProps.surname.substring(
    0,
    TRUNCATED_MAX_SURNAME_CHARS,
  )}${TRUNCATED_SURNAME_ELLIPSIS}`,
});
}