我正在使用高阶组件来装饰我的组件。
const HOC = (WrappedComponent) => (props) => {
return (
<span>
<p>HOC Comp</p>
<WrappedComponent {...props}/>
</span>
)
}
我喜欢这里解释的模式:React Higher Order Components in depth
但是我有一个问题,因为HOC导致React重新创建我的组件树而不是更新树。这里很好地解释了React Reconciliation。 HOC返回一个匿名函数,React不知道它实际上是在渲染相同的组件。这对性能不利,并使我的输入字段失去焦点。
如果没有React在每个render()
上重新创建我的树,我怎么能使用HOC组件?
示例代码:
class Input extends React.Component {
componentWillMount() {
console.log('input component will mount');
}
componentWillUnmount() {
console.log('input component will unmount');
}
render() {
return (
<span>
<input value={this.props.value} onChange={this.props.onChange}/>
</span>
);
}
}
const HOC = (WrappedComponent) => {
const Help = (props) => {
return (
<span>
<WrappedComponent {...props}/>
<p>{props.help}</p>
</span>
)
};
return Help;
}
class MyComponent extends React.Component {
constructor (props) {
super(props);
this.state = {value : 'start value'}
}
onChange(event) {
this.setState({value : event.target.value});
}
render() {
const Element = HOC(Input);
return (
<span>
<Element
value={this.state.value}
onChange={this.onChange.bind(this)}
/>
</span>
)
}
}
ReactDOM.render(
<MyComponent />,
document.getElementById('container')
);
请参阅Fiddle example(请在浏览器的控制台中查看,每次更改输入时都会看到输入组件中的挂载和卸载日志,并失去焦点)
答案 0 :(得分:6)
您不必在渲染功能中创建class MyComponent extends React.Component {
constructor (props) {
super(props);
this.state = {value : 'start value'};
this.element = HOC(Input);
}
...
。相反,您可以在构造函数中创建它:
<span>
<this.element
value={this.state.value}
onChange={this.onChange.bind(this)}
/>
</span>
并在你的渲染函数中使用它:
this.element
如果需要,您可以更新componentWillReceiveProps()
或componentWillUpdate()
中的colors = set([toy.color for toy in toys])
groups = [ [toy for toy in toys if toy.color == color] for color in colors]
。
更新:fiddle
答案 1 :(得分:1)
这是我通过children
扩展具有受控输入元素的功能组件的方式,并且不会失去焦点。
/* import React, { Fragment, useState } from 'react' */
const { Fragment, useState } = React
/* HOC */
const withInput = Base => (props) => {
const [inputValue, setValue] = useState()
return <Base children={
<Fragment>
{props.children}<br />
<input
value={inputValue}
onChange={({ target: { value }}) => setValue(value)}
placeholder="input from hoc" /><br />
<span>inputValue: {inputValue}</span>
</Fragment>
} />
}
/* Component */
const MyComponent = ({children}) => (
<span>
<span>own elements</span><br />
{children}
</span>
)
const MyComponentWithInput = withInput(MyComponent)
ReactDOM.render(<MyComponentWithInput>passed children</MyComponentWithInput>, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>