React组件(textarea)不会使用更新状态的新样式重新呈现

时间:2017-06-24 20:18:47

标签: reactjs textarea state styled-components

两个文本区域略有不同,我无法理解为什么第二个区域不起作用。

Here's the Codepen

const StyledTextarea = styled.textarea`
  display: block;
  font-size: 20px;
  line-height: 40px;
  min-height: 120px;
  overflow: hidden;
  padding: 0 7px;
  margin: 0 0 30px;
  resize: none;
  width: 500px;
`;

const Label = styled.span`
  color: ${props => props.green ? '#00BB00' : 'red'};
  font-size: 1.5em;
`;

const App = () => {
  return(
    <div>
      <Label green>✅ Textarea1 - Working </Label>
      <Textarea1 />
      <Label>❌ Textarea2 - Not working </Label>
      <Textarea2 />
    </div>
  )
}

class Textarea1 extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
          value: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda voluptas deleniti at, molestias in amet dolore voluptatem atque, modi minus ipsam dignissimos...',
          scrollHeight: 0,
        }
    }

    onChange(e) {
      const t = e.target;
      t.style.height = 'auto';
      t.style.height = `${t.scrollHeight}px`;
      this.setState({value: t.value});
    }

    render() {
        return (
            <StyledTextarea
              value={this.state.value}
              onChange={this.onChange.bind(this)}
            />
        );
    }
}

class Textarea2 extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
          value: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda voluptas deleniti at, molestias in amet dolore voluptatem atque, modi minus ipsam dignissimos...',
          scrollHeight: 0,
        }
    }

    onChange(e) {
      const bugger = e.target;
       console.log('style.height before it is set to auto: ', bugger.style.height)
      bugger.style.height = 'auto';
       console.log('style.height after it is set to auto (obviously): ', bugger.style.height)
       console.log('.scroll height: ', bugger.scrollHeight);
      this.setState({
        scrollHeight: bugger.scrollHeight,
        value: bugger.value
      });
    }

    render() {
        return (
            <StyledTextarea
              style={{height: `${this.state.scrollHeight}px`}}
              value={this.state.value}
              onChange={this.onChange.bind(this)}
            />
        );
    }
}

两者都使用类似的方式来保持其高度与内容的高度同步。但是,第二个,我认为应该使用新的style.height(来自更新的状态)重新渲染,不适用新的样式。在控制台上查看有问题的值 - 即使在分配新值后,style.height也会保持“自动”状态。 如果你只按Enter和Backspace,它就可以工作。

我不明白是什么?

1 个答案:

答案 0 :(得分:0)

这是一个棘手的问题,与使用React的styled-components库比使用React代码本身更相关。在Textarea1的渲染中,您正在创建一个传递了样式道具的StyledTextarea。不幸的是,使用样式化组件创建的组件会忽略此道具。

当使用带有反应的样式组件时,你应该拔出你的道具并将它们应用到你的css,如this code-pen所示:

const styled = styled.default;

const Button = styled.button`
  background: red;
  border-radius: 8px;
  color: white;
  height: ${props => props.small ? 40 : 60}px;
  width: ${props => props.small ? 60 : 120}px;
`;

class Application extends React.Component {
  render() {
    return (
      <div>
        <Button small>Click Me</Button>
        <Button large>Click Me</Button>
      </div>
    )
  }
}

ReactDOM.render(<Application />, document.getElementById('content'));

要解决您的问题,您必须在StyledTextArea中提取您的style.height支持,并在Textarea2.onChange结束时将您的身高重置为''。以下是包含这些更改的代码。请注意,这会破坏在Textarea1中完成的大小调整:

const styled = styled.default;

const StyledTextarea = styled.textarea`
  display: block;
  font-family: PT Sans;
  font-size: 20px;
  line-height: 40px;
  min-height: 120px;
  overflow: hidden;
  padding: 0 7px;
  margin: 0 0 30px;
  resize: none;
  width: 500px;
  // one update here
  height: ${props => (props.style && props.style.height) ? props.style.height + 'px' : '0px'};
`;

const Label = styled.span`
  color: ${props => props.green ? '#00BB00' : 'red'};
  font-size: 1.5em;
`;

const App = () => {
  return(
    <div>
      <Label green>✅ Textarea1 - Working </Label>
      <Textarea1 />
      <Label>❌ Textarea2 - Not working </Label>
      <Textarea2 />
    </div>
  )
}

class Textarea1 extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
          value: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda voluptas deleniti at, molestias in amet dolore voluptatem atque, modi minus ipsam dignissimos...',
          scrollHeight: 0,
        }
    }

    onChange(e) {
      const t = e.target;
      t.style.height = 'auto';
      t.style.height = `${t.scrollHeight}px`;
      this.setState({value: t.value});
    }

    render() {
        return (
            <StyledTextarea
              value={this.state.value}
              onChange={this.onChange.bind(this)}
            />
        );
    }
}

class Textarea2 extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
          value: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda voluptas deleniti at, molestias in amet dolore voluptatem atque, modi minus ipsam dignissimos...',
          scrollHeight: 0,
        }
    }

    onChange(e) {
      const bugger = e.target;
       console.log('style.height before it is set to auto: ', bugger.style.height)
      bugger.style.height = 'auto';
       console.log('style.height after it is set to auto (obviously): ', bugger.style.height)
       console.log('.scroll height: ', bugger.scrollHeight);
      this.setState({
        scrollHeight: bugger.scrollHeight,
        value: bugger.value
      });
      // another update here
      bugger.style.height = '';
    }

    render() {
      console.log(this.state.scrollHeight);
        return (
            <StyledTextarea
              style={{height: this.state.scrollHeight}}
              value={this.state.value}
              onChange={this.onChange.bind(this)}
            />
        );
    }
}

ReactDOM.render(<App />, document.getElementById('root'));

最后一点,您使用的第二种方法肯定是更优选的方法!通过处理程序而不是渲染方法修改组件样式并不理想。