this.setState не обновляет состояние dataSource после выборки из Firebase в RN - PullRequest
0 голосов
/ 03 октября 2018

в componentDidMount Я ввел функцию, которая извлекает некоторые данные из Firebase и может вызываться каждый раз, когда пользователь хочет получить снова.

Проблема в том, что первая выборка не обновляется.После создания я хочу обновить массив источника данных, но он не обновляется.он обновляется через состояние вращения при загрузке.

Вот код:

    constructor(props) {
    super(props);

    const rowHasChanged = (r1, r2) => r1 !== r2
    // DataSource configured
     ds = new ListView.DataSource({ rowHasChanged })

    this.state = { 
        isLoading: true,
        dataSource: ds,
    };
}

componentDidMount() {
    this.fetchGroups()     
}
    fetchGroups() {
    firebase.database().ref('groups/numbers').once("value", (snap) => {
        snap.forEach((snapshot) => {
            firebase.database().ref('groups/' + snapshot.val()).once('value').then((snapshot) => {
                getparticipant = snapshot.val().participant
            var instantPrice
                switch (true) {
                    case (getparticipant <= 3):
                        instantSpace= snapshot.val().spaceOne
                        break;
                    case (getparticipant <= 10):
                        instantSpace= snapshot.val().spaceTwo
                        break;
                    case (getparticipant <= 20):
                        instantSpace= snapshot.val().spaceThree
                        break;
                    case (getparticipant > 20):
                        instantSpace= snapshot.val().spaceFourth
                        break;
                }
            dataObject.push({
                title: snapshot.val().type + ' ' + snapshot.val().brand,
                groupId: snapshot.val().groupID,
                description: snapshot.val().model,
                icon: snapshot.val().icon,
                partners: snapshot.val().participant,
                finalDate: snapshot.val().timeMerge,
                space: instantSpace,
                photo: snapshot.val().adminPhoto
                })
            }) 
        })
    }).then(() => {
        console.log(dataObject)
        this.setState({
            dataSource: ds.cloneWithRows(dataObject),
            isLoading: false
        })
        console.log(this.state.isLoading)
        console.log(this.state.dataSource)
    })
}

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

Попробуйте инициировать ваше состояние с пустым списком, например:

this.ds = new ListView.DataSource({
    rowHasChanged: (row1, row2) => row1 !== row2
});

this.state = { 
    dataSource: this.ds.cloneWithRows([]),
    isLoading: true
};

Обратите внимание на пустое значение [] внутри функции cloneWithRows.

Затем создайте новый массив и, когдаВы извлекаете данные, помещаете их в новый массив и обновляете состояние методом Object.assign.Как то так:

fetchGroups() {
    var dataObject = []

    firebase.database().ref('groups/numbers').once("value", (snap) => {
        snap.forEach((snapshot) => {
            firebase.database().ref('groups/' + snapshot.val()).once('value').then((snapshot) => {
                getparticipant = snapshot.val().participant;
                var instantSpace;
                switch (true) {
                    case (getparticipant <= 3):
                        instantSpace= snapshot.val().spaceOne
                        break;
                    case (getparticipant <= 10):
                        instantSpace= snapshot.val().spaceTwo
                        break;
                    case (getparticipant <= 20):
                        instantSpace= snapshot.val().spaceThree
                        break;
                    case (getparticipant > 20):
                        instantSpace= snapshot.val().spaceFourth
                        break;
                }

                dataObject.push({
                    title: snapshot.val().type + ' ' + snapshot.val().brand,
                    groupId: snapshot.val().groupID,
                    description: snapshot.val().model,
                    icon: snapshot.val().icon,
                    partners: snapshot.val().participant,
                    finalDate: snapshot.val().timeMerge,
                    price: instantPrice,
                    photo: snapshot.val().adminPhoto
                });

                // Update the state
                this.setState({ 
                   dataSource: this.ds.cloneWithRows(Object.assign({}, dataObject)) 
                });
            });
        });
    });
}
0 голосов
/ 03 октября 2018

setState является асинхронной операцией .Поэтому у вас не будет его последнего значения сразу.

Если вам нужен доступ к его последним изменениям, вы можете использовать:

this.setState({
  dataSouce: ds.cloneWithRows(dataObject),
  isLoading: false,
}, () => {
  console.log(this.state.isLoading)
  console.log(this.state. dataSource)
})

const asyncOperation = () => new Promise(resolve => setTimeout(resolve, 2000))

class App extends React.Component {
  constructor() {
    super()

    this.state = {
      loading: false,
      counter: 0
    }

    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    this.setState({ loading: true })
    
    asyncOperation()
      .then(() => {
        console.log('Current state value:', this.state.counter)
        
        this.setState({
          counter: this.state.counter + 1,
          loading: false,
        }, () => {
          console.log('New state value:', this.state.counter)
        })
      })
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          Click-me
        </button>
        <p>Counter: {this.state.counter}</p>
        {this.state.loading && <p>Loading...</p>}
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
...