我有一个像这样的小型演示组件:
function MyList({data, uppercaseMe, lowercaseMe}) {
return <ul>
{data.map(item =>
<li>{item} -
<button onClick={() => uppercaseMe(item)}>Uppercase me!</button>
<button onClick={() => lowercaseMe(item)}>Lowercase me!</button>
</li>)}
</ul>;
}
然后我想用三个HOC来装饰MyList:
const WithData = (Component) => {
return class extends React.Component {
constructor(props) {
super(props);
this.state= {data:['one', 'two', 'three', 'four', 'five']};
};
render() {
return <Component {...this.props} data={this.state.data} />;
}
}
};
const WithUppercase = (Component) => {
return class extends React.Component {
uppercaseMe = (item) => {
// how to access WithData state from here?
console.log(item.toUpperCase());
};
constructor(props) {
super(props);
};
render() {
return <Component {...this.props} uppercaseMe={this.uppercaseMe}/>;
}
}
};
const WithLowercase = (Component) => {
return class extends React.Component {
lowercaseMe = (item) => {
// how to access WithData state from here?
console.log(item.toLowerCase());
};
constructor(props) {
super(props);
};
render() {
return <Component {...this.props} lowercaseMe={this.lowercaseMe}/>;
}
}
};
像这样:
const ComposedList = WithLowercase(WithUppercase(WithData(MyList)));
不幸的是,我不知道如何在WithLowercase或WithUppercase中更改WithData的状态。
如何将一个HOC的状态暴露给链中的另一个HOCS?
答案 0 :(得分:8)
你不想直接暴露国家。你想要做的是将一个函数作为prop传递给包装组件,以允许你更新状态。
因此,如果我们使用HOC并添加一些代码,创建一个函数来更新其状态,现在可以传递给它的子组件:
const WithData = (Component) => {
return class extends React.Component {
constructor(props) {
super(props);
this.state= {data:['one', 'two', 'three', 'four', 'five']};
}
update (data) {
this.setState({ data });
}
render() {
return <Component onUpdate={this.update} {...this.props} data={this.state.data} />;
}
}
};
现在,我们可以在其中一个子组件中使用它:
const WithUppercase = (Component) => {
return class extends React.Component {
uppercaseMe = (item) => {
const itemIndex = this.props.data.indexOf(item);
const newData = this.props.data.slice();
newData[itemIndex] = item.toUpperCase();
this.props.onUpdate(newData); // update WithData state here
};
constructor(props) {
super(props);
};
render() {
// onUpdate function is once again passed to child components
// implicitly through props if you need to call it again
return <Component {...this.props} uppercaseMe={this.uppercaseMe}/>;
}
}
};
答案 1 :(得分:1)
将数据传递回组件链本质上违背了反应使用的模式,这是数据流的一种方式。数据下降但永远不会恢复。就像@FuriousD所说的那样,你应该让lowerCase和upperCase方法可用于链中的组件。您可以使用context执行此操作。
“在某些情况下,您希望通过组件树传递数据,而无需在每个级别手动传递道具。您可以使用功能强大的”上下文“API直接在React中执行此操作。”
以下是使用代码更新版本的示例。
const WithUpperCase = (Component) => {
class _WithUpperCase extends React.Component {
getChildContext() {
return {
uppercaseMe: this.uppercaseMe,
}
}
uppercaseMe = (item) => {
return item.toUpperCase()
};
render() {
return <Component {...this.props} />;
}
}
_WithUpperCase.childContextTypes = {
lowercaseMe: PropTypes.func,
}
return _WithUpperCase;
};
const WithLowercase = (Component) => {
class _WithLowercase extends React.Component {
getChildContext() {
return {
lowercaseMe: this.lowercaseMe,
}
}
lowercaseMe = (item) => {
return item.toLowerCase()
};
render() {
return <Component {...this.props} />;
}
}
_WithLowercase.childContextTypes = {
lowercaseMe: PropTypes.func,
}
return _WithLowercase;
};
function MyList({ data }, { uppercaseMe, lowercaseMe }) {
return (
<ul>
{
data.map(item => (
<li>{item} -
<button onClick={() => uppercaseMe(item)}>Uppercase me!</button>
<button onClick={() => lowercaseMe(item)}>Lowercase me!</button>
</li>
))
}
</ul>
);
}
MyList.contextTypes = {
// Need to import the PropTypes library
uppercaseMe: PropTypes.func,
lowercaseMe: PropTypes.func,
};