我知道这种操作可能是不推荐的,但在我的情况下,我找不到任何其他解决方案。我有一个组件实例的引用,我想要达到它的父级,更新样式和重新渲染。 如果你认为这很疯狂,我会描述这个问题。
我正在使用带有粘性标题的节列表,它会生成这样的树(简化):
<VirtualizedList>
<CellRenderer> //internal component rendered by Virtualized list with flex: 1
<MyComponent ref=(instance) => changeStylesFunc(instance) />
</CellRenderer>
</VirtualizedList>
我正在传递MyComponent
但事件如果我将其样式设置为width: 80
包装器(CellRenderer)将具有全宽,因为它自己的样式。
T不能更改CellRenderer
样式,因为这会涉及RN源代码更改。
我的想法:
因为我已经参考MyComponent
实例,所以我也可以通过以下方式访问父实例(CellRenderer
):
const cellRenderer = ref._reactInternalInstance._currentElement._owner
我被困在这里,因为我没有更新cellRenderer
的样式。
我尝试了什么:
cellRenderer._instance.props.styles = { width: 80 };
cellRenderer._currentElement.props.styles = { width: 80 };
答案 0 :(得分:2)
我认为你需要的是Lifting State Up:
通常,有几个组件需要反映相同的变化数据。我们 建议将共享状态提升到最近的共同状态 祖先。让我们看看这是如何运作的。
在您的情况下,<CellRenderer />
和<MyComponent />
需要反映相同的更改数据。
class MyCell extends Component {
constructor(props) {
super(props);
this.state = {
cellStyle: { flex: 1 }
}
}
changeStyleFunc(newStyle) {
this.setState({ cellStyle: newStyle });
}
render() {
return (
<CellRenderer style={this.state.cellStyle}>
<MyComponent onChangeStyle={(newStyle) => changeStylesFunc(newStyle)} />
</CellRenderer>
);
}
}
所以你可以使用:
<VirtualizedList>
...
<MyCell />
...
</VirtualizedList>
注意:
不要像ref
那样修改道具。它不起作用,因为An update can be caused by changes to props or state。不是通过改变他们内在的,不可改变的价值。
答案 1 :(得分:0)
这是另一种更改<SectionList />
项目的视觉宽度的方法,而不会触及<VisualizedList />
。
export class Home extends Component {
constructor(props) {
super(props);
this.state = {};
}
getUidFromSectionAndRow(section, row) {
return `${section}_${row}`;
}
getStyleWithUid(uid) {
return this.state[uid] || {flex: 1};
}
setStyleWithUid(uid, style) {
this.setState({
[uid]: style
});
}
render() {
let sectionData = [
[1,2,3],
[1,2,3]
]
return (
<SectionList
renderItem={({item}) => {
return (
<View style={[this.getStyleWithUid(item.key), {flexDirection: 'row', marginVertical: 10}]}>
<Text style={{flex: 1, textAlign: 'center', textAlignVertical: 'center', backgroundColor: 'white'}}>This is number {item.value} row.</Text>
<TouchableOpacity onPress={() => {
this.setStyleWithUid(item.key, {width: 200});
}}>
<Text style={{width: 80, height: 50, backgroundColor: 'purple', textAlign: 'center', textAlignVertical: 'center', color: 'white'}}>Change Width</Text>
</TouchableOpacity>
</View>
)
}}
renderSectionHeader={ ({section}) => <Text style={{fontSize: 20, fontWeight: '600'}}>{section.title}</Text> }
sections={
[
{ data: [
{
key: this.getUidFromSectionAndRow(1, 1),
value: 1
},
{
key: this.getUidFromSectionAndRow(1, 2),
value: 2
},
{
key: this.getUidFromSectionAndRow(1, 3),
value: 3
}
], title: 'Section 1' },
{ data: [
{
key: this.getUidFromSectionAndRow(2, 1),
value: 1
},
{
key: this.getUidFromSectionAndRow(2, 2),
value: 2
},
{
key: this.getUidFromSectionAndRow(2, 3),
value: 3
}
], title: 'Section 2' },
]
}
/>
);
}
}
这70行代码应该足够简单,关键是让每个部分/行反映一个唯一的状态键。
因此,每次使用setStyleWithUid()
设置样式时,它只会影响该特定行。