0

我正在尝试使用 React Native ListView 对两行的交换进行动画处理

这是我的数据源代码(都在我的渲染方法中):

const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1.id !== r2.id})
var dataSource = ds.cloneWithRows(state.todoLists[this.props.index].todos.slice())

这是我的交换代码(使用 MobX):

    var {todo, i} = forID(state.todoLists[list].todos, id) //Gets index and todo from  id
    state.todoLists[list].todos.splice(i, 1)
    state.todoLists[list].todos.push({...todo, done: !todo.done})

如您所见,由于数组项只是向下移动,因此等价性保持不变。

如果我尝试 LayoutAnimation,我会感到奇怪: 在此处输入图像描述

有任何想法吗?

4

1 回答 1

1

我怀疑问题在于(根据您所说的)您正在render方法中创建 DataSource 。您应该ListView.DataSource在构造函数(或componentWillMount)中创建对象,然后cloneWithRows在数据更改时调用,而不是在render. 问题是,通过在每次渲染上重新创建一个新的 DataSource,它永远不会调用该rowHasChanged函数,因为数据源中从来没有以前的状态。

示例正确实现

在下面的示例中,我在构造函数中设置数据源并将其存储在状态中。然后一旦安装,我让它加载待办事项,并更新状态下的数据源,这将触发重新渲染。

然后,当您想将待办事项移动到底部时,您会调用this.moveItemToBottom(id),它会修改状态,并更新状态上的数据源,并在设置好 LayoutAnimation 后重新渲染。

class TodoList extends Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      ds: new ListView.DataSource({
        rowHasChanged: (r1, r2) => (r1 !== r2),
      }),
    }; 
  }

  componentDidMount() {
    loadInitialData();
  }
  
  loadInitialData() {
    // Do something to get the initial list data
    let todos = someFuncThatLoadsTodos();

    this.setState({
      ds: this.state.ds.cloneWithRows(todos),
    });
  }

  moveItemToBottom(id) {
    // get your state somewhere??
    let todos = state.todoLists[list].todos;

    let {todo, i} = forID(state.todoLists[list].todos, id)
    todos.splice(i, 1).push({...todo, done: !todo.done});
    
    LayoutAnimation.easeInEaseOut();
    this.setState({
      ds: this.state.ds.cloneWithRows(todos),
    });
  }
  
  render() {
    return (
      <ListView
        dataSource={this.ds}
        // Other props
      />
    );
  }
}

编辑/注意:我的示例没有考虑与 MobX 有任何关系。我没有使用它,但粗略地看,您可能需要观察待办事项列表并在数据源更新时更新它,并且只需让该moveItemToBottom方法更新 MobX 状态并依赖可观察到setState的克隆数据源。

于 2016-10-09T02:27:29.320 回答