更新组件的实例道具/样式

时间:2017-12-13 09:12:40

标签: reactjs react-native

我知道这种操作可能是不推荐的,但在我的情况下,我找不到任何其他解决方案。我有一个组件实例的引用,我想要达到它的父级,更新样式和重新渲染。 如果你认为这很疯狂,我会描述这个问题。

我正在使用带有粘性标题的节列表,它会生成这样的树(简化):

<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 };

2 个答案:

答案 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 />

结果:

enter image description here

代码:

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()设置样式时,它只会影响该特定行。