【问题标题】:React component (textarea) won't re-render with new style from updated stateReact 组件(textarea)不会使用更新状态的新样式重新渲染
【发布时间】:2017-11-28 03:58:29
【问题描述】:

这两个文本区域只是略有不同,我不明白为什么第二个不起作用。

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 ,它就可以工作。

什么是我不明白的?

【问题讨论】:

    标签: reactjs textarea state styled-components


    【解决方案1】:

    这是一个棘手的问题,与您在 React 中使用 styled-components 库有关,而不是您的 React 代码本身。在您的 Textarea1 的渲染中,您正在创建一个 StyledTextarea 并传入了一个 style 属性。不幸的是,这个属性被使用 styled-components 创建的组件忽略了。

    当使用带有 react 的 styled-components 时,你应该将你的 props 拉出来并将它们应用到你的 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'));
    

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

    【讨论】:

    • 谢谢哥们,它现在可以工作了!您可以只使用 height 道具并像这样使用它:height: ${props =&gt; props.height &amp;&amp; ${props.height}px}; 我已经更新了 codepen 以包含工作示例。但是,style 属性被 styled component 忽略并不完全正确。这是一个link 到一个简化的范围滑块,它尊重它(仅适用于点击,但你明白了)。似乎 styled component 不能保证将 style 传递给底层 DOM 节点,但它可以。我想知道哪个是设计使然。
    • 在旁注中,您认为是否值得使用styled components,在性能和复杂性方面来管理经常变化的值,例如元素被拖动时的位置?
    • 1) 我很高兴它有帮助! 2)是的,你刚刚通过高度的改进似乎更干净。好决定。 3)奇怪的是它有时会起作用。我的猜测是它可能与生成的 dom 元素的类型有关?我注意到在您的示例中创建了 &lt;div&gt;,而在原始示例中创建了 &lt;textarea&gt;
    • 4) 这是一个很好的问题,但我没有充分利用库来告诉你,快速搜索“样式化组件性能”并没有为我带来任何好处。您可以尝试多搜索一下,查看他们的源代码,或者看看是否有一个好地方可以询问他们的社区。​​span>
    猜你喜欢
    • 1970-01-01
    • 2021-05-19
    • 2022-01-26
    • 2020-09-05
    • 2019-06-17
    • 1970-01-01
    • 2019-02-27
    • 1970-01-01
    相关资源
    最近更新 更多