React Native(搭配Redux)如何通过编程方式实现开关动画

5

我有一个组件,里面包含Switch组件。整个组件都可以点击。当您点击此组件时,它会触发dispatch(修改redux存储),并导致重新渲染此组件。

我需要的是不重新渲染整个组件,而只是将Switch组件动画到正确的状态。

类似于这样:

<TouchableOpacity onPress={onPress}>
    <Text>{this.props.title}</Text>
    <Switch value={this.state.active}/>
</TouchableOpacity>

有什么想法吗?

我发现这是一个很常见的用例,我知道我将遇到许多类似的情况,所以我需要这种行为,但我在网络上找不到任何示例或解决方案。也许我只是漏了什么。

谢谢

--- 编辑 ---

我也尝试过这个。 我尝试使用shouldComponentUpdate禁用更新,我尝试仅在willRecieveProps和/或toggle中设置状态,甚至没有toggle。 我还尝试了LayoutAnimation的玩法。 但是都无济于事,this.setState()只是不能动画切换组件。 我还尝试玩弄this._switch._rctSwitch.setNativeProps({ value:nextProps.active }),但这也行不通(而且_rctSwitch的问题很大)。

class ViewWithSwitchInside extends React.Component {
    constructor(props) {
        super(props)
        this.toggle = this.toggle.bind(this);
        this.state = {
            active: props.active
        }
    }

    componentWillReceiveProps(nextProps) {
        if (this.state.active != nextProps.active) {
            this.setState({ active: nextProps.active })
        }
    }

    toggle() {
        let newValue = !this.state.active
        this.setState({
            active: newValue,
        })
        if (typeof this.props.onClick === 'function') {
            this.props.onClick(newValue)
        }
    }

    render() {
        return (
            <TouchableWithoutFeedback onPress={this.toggle}>
                <View>
                    <Text>{this.props.title}</Text>
                    <Switch value={this.state.active} />
                </View>
            </TouchableWithoutFeedback>
        )
    }
}

你能否尝试像这样做呢?https://dev59.com/J1gR5IYBdhLWcg3wyv5c - Tom
我不确定你指的是什么,因为那个问题与动画无关。但是,我还是编辑了我的原始问题。这是一个最小化的例子,请尝试一下,它只是没有动画效果。只有在直接点击该开关时,更改才会被动画化。我不确定这是否是一个错误,但对我来说它看起来像基本功能。 - trubi
@trubi:我可能有同样的问题,但我不完全理解你的问题。我有一个开关,当你点击它时会有动画效果,但我还想根据其他用户交互来切换它。但是当我只用setState来改变它时,它会立即跳到另一个位置,没有平滑的动画效果。这与你的问题不同吗? - hippietrail
这听起来就是我的问题。你有解决方案吗? - trubi
1个回答

0

你不能从父组件中渲染单个子元素。即使你以某种方式能够更改开关所依赖的变量的值,除非重新渲染父组件,否则它不会显示。

我尝试使用全局变量来设置开关的值,并使用shouldComponentUpdate()阻止了父组件的重新渲染,你可以在这里阅读更多相关信息。

这是我的结果:

这是我的应用程序的初始状态。该全局变量被设置为false,并且父组件已经被渲染。

enter image description here

现在我通过轻触 Switch 包围的 View 来将全局变量更改为 true,然后它就改变了。

enter image description here

但是在视觉上没有任何变化,只有变量改变了,开关没有改变。

然后我通过按下屏幕底部的“重新渲染”文本来更改state(与Switch组件无关的更改),结果如下:

Result of re-rendering

这是上述应用程序的代码:
var isActive = false; //global variable
class Test extends Component {
  constructor(props) {
    super(props);
    this.state={active:false, irrelevantState: true};
  }

  test(foo){
    console.log("Attempting to change", foo);
    isActive = foo;
  }

  shouldComponentUpdate(nextProps, nextState){
    if(this.state.active != nextState.active){//If the new state is different than the previous, stop rendering.
      this.test(nextState.active);
      return false;
    }else { //else, re-render everything
      return true;
    }
  }

  render(){
    console.log("Test re-render");
    return(
      <View style={{flex:1}}>
        <TouchableOpacity onPress={()=>{this.setState({active:!this.state.active})}} style={{flex:1, marginTop:20}}>
          <Text>Test Component</Text>
          <Switch value={isActive}/>
        </TouchableOpacity>
        <TouchableOpacity onPress={()=>{this.setState({active:true})}} style={{flex:1, marginTop:20}}>
          <Text>Test Component</Text>
          <Switch value={isActive}/>
        </TouchableOpacity>
        <TouchableOpacity style={{height:20}} onPress={()=>this.setState({irrelevantState:false})}>
          <Text> Re-render</Text>
        </TouchableOpacity>
      </View>
    )
  }
}

你最好的选择是找到一种聪明的方法,只有当this.state.active和其他必需的状态改变以使你的应用程序正常运行时,才重新渲染,忽略其他更改。


每个组件都需要一个全局变量听起来很疯狂。我不需要重新渲染单个子组件。整个组件可以(也应该)重新渲染。我只需要用动画渲染那个开关。或者更像是根本不渲染,只需在那个开关上设置isOn()。这就是原生iOS开关的工作方式。当您调用此方法时,它会自行进行动画处理。setNativeProps()怎么样?还是我应该实现自己的本地开关包装器? - trubi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接