React 组件(textarea)不会使用更新状态的新样式重新渲染
React component (textarea) won't re-render with new style from updated state
这两个文本区域只是略有不同,我不明白为什么第二个区域不起作用。
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 即使在分配新值后仍保持 'auto'。
如果您只按 Enter 和 Backspace,它会起作用。
我不明白什么?
这是一个棘手的问题,与您在 React 中使用 styled-components 库比您的 React 代码本身更相关。在 Textarea1
的渲染中,您正在创建一个带有传入样式道具的 StyledTextarea
。不幸的是,使用 styled-components 创建的组件会忽略此道具。
当使用带有 react 的 styled-components 时,你应该将你的道具拉出来并将它们应用到你的 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'));
最后一点,您使用的第二种方法绝对是更可取的方法!通过处理程序而不是渲染方法修改组件样式并不理想。
这两个文本区域只是略有不同,我不明白为什么第二个区域不起作用。
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 即使在分配新值后仍保持 'auto'。
如果您只按 Enter 和 Backspace,它会起作用。
我不明白什么?
这是一个棘手的问题,与您在 React 中使用 styled-components 库比您的 React 代码本身更相关。在 Textarea1
的渲染中,您正在创建一个带有传入样式道具的 StyledTextarea
。不幸的是,使用 styled-components 创建的组件会忽略此道具。
当使用带有 react 的 styled-components 时,你应该将你的道具拉出来并将它们应用到你的 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'));
最后一点,您使用的第二种方法绝对是更可取的方法!通过处理程序而不是渲染方法修改组件样式并不理想。