#reactjs #react-native #expo
#reactjs #react-native #выставка
Вопрос:
Итак, я пытаюсь создать простое приложение с expo и expo audio, которое будет генерировать список звуковых кнопок и текста. Но я не могу понять, как работает react в отношении перерисовки setState ВНЕ componentWillMount и как переделать soundobject с новым URI
Итак, прямо сейчас это будет работать, но воспроизводится только ПЕРВЫЙ uri, я предполагаю, это потому, что объект все еще существует.
И это не изменит состояние кнопки, я знаю, это потому, что react по какой-то причине не может видеть ее изменение из FlatList
Это работает вне этого, если я создаю только одну кнопку в режиме рендеринга.
FlatList отобразит setStates, если я использую LegacyImplementation= true .. Но я предупредил, что это устарело. И он отображает его для всех кнопок одновременно
Это мой класс-обработчик:
export class TSSGetter extends React.Component {
constructor(props){
super(props);
this.state ={
isLoading: true,
playingStatus: "Play"
}
}
retrieveData() {
const endpoint = 'http://127.0.0.1:3333/get'
const data = {
"userId": "123412341234",
"hmac": "detteerikkeenrigtighmac"
}
return new Promise((resolve, reject) => {
fetch(endpoint, {
method: 'POST',
headers: {
'Accept': 'application/json',
'content-type':'application/json'
},
body: JSON.stringify(data)
})
.then((resp) => {
console.log('hej return')
return resp.json();
})
.then((resp) => {
resolve(resp);
console.log('resp')
}).catch(function(error) {
console.log(error,'naeh')
});
});
}
componentDidMount(){
this.retrieveData()
.then((resp) => {
var pages = resp.books.contentObjects
pages.map((userData) => {
console.log('superduper pages', userData.contentObjectId)
})
this.setState({
isLoading: false,
dataSource: resp.books.contentObjects,
dataroot: resp.books
});
}).catch((err) => {
//handle error
console.log("Api call error2");
alert(err);
})
}
async _playRecording(AudioURL) {
console.log(AudioURL)
const { sound } = await Audio.Sound.createAsync(
{uri: AudioURL},
{
shouldPlay: true,
isLooping: true,
},
this._updateScreenForSoundStatus,
);
this.sound = sound;
this.setState({
playingStatus: 'playing'
});
}
_updateScreenForSoundStatus = (status) => {
if (status.isPlaying amp;amp; this.state.playingStatus !== "playing") {
this.setState({ playingStatus: "playing" });
} else if (!status.isPlaying amp;amp; this.state.playingStatus === "playing") {
this.setState({ playingStatus: "donepause" });
}
};
async _pauseAndPlayRecording() {
if (this.sound != null) {
if (this.state.playingStatus == 'playing') {
console.log('pausing...');
await this.sound.pauseAsync();
console.log('paused!');
this.setState({
playingStatus: 'donepause',
});
} else {
console.log('playing...');
await this.sound.playAsync();
console.log('playing!');
this.setState({
playingStatus: 'playing',
});
}
}
}
_syncPauseAndPlayRecording() {
if (this.sound != null) {
if (this.state.playingStatus == 'playing') {
this.sound.pauseAsync();
} else {
this.sound.playAsync();
}
}
}
_playAndPause = (AudioURL) => {
console.log(AudioURL)
switch (this.state.playingStatus) {
case 'Play':
this._playRecording(AudioURL);
break;
case 'donepause':
case 'playing':
this._pauseAndPlayRecording();
break;
}
}
render(){
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
const styling = {
flex: 1,
paddingTop:10
// flexDirection: 'row'
}
const data = this.state.dataroot;
return(
<View style={styles.container}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) =>
<View>
<TouchableOpacity style={styles.button} onPress={() => this._playAndPause(item.AudioURL)}>
<Text style={styles.buttonText}>
{this.state.playingStatus} {item.contentObjectId}
</Text>
</TouchableOpacity>
<Text style={styles.description}>
{item.text},
</Text>
</View>
}
keyExtractor={(item, index) => item.contentObjectId}
/>
</View>
);
}
}
ОБНОВЛЕНИЕ: установка ExtraData={this.state} в flatlist обновляет кнопку.. Но все кнопки. Как мне изменить область действия кнопки?
Комментарии:
1. Вы хотите сказать, что каждая строка должна вести себя независимо, т. Е. пауза, воспроизведение должно быть независимым для каждого элемента в
FlatList
?
Ответ №1:
Вы могли бы создать определенный компонент для элементов в FlatList
. После этого каждый из элементов будет иметь свое собственное состояние.
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import { FlatList } from "react-native-gesture-handler";
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => index.toString()}
data={[1, 2, 3, 4, 5]}
renderItem={({ item }) => <Sound />}
/>
</View>
);
}
}
class Sound extends Component {
constructor() {
super();
this.state = {
status: "IDLE"
};
}
onChangeState = value => {
this.setState({
status: value
});
};
render() {
const { status } = this.state;
return (
<View style={{width: 200,paddingVertical: 10}}>
<Text>Status: {status}</Text>
<View style={{ flex: 1,flexDirection: "row", justifyContent: "space-between" }}>
<Text onPress={() => this.onChangeState("PLAYING")}>PLAY</Text>
<Text onPress={() => this.onChangeState("STOPPED")}>STOP</Text>
<Text onPress={() => this.onChangeState("PAUSED")}>PAUSE</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 100,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center"
}
});
Ответ №2:
Я проверил в документах, здесь, и я увидел, что он будет повторно отображаться, только если вы передадите state prop, смотрите Это объяснение:
Передавая ExtraData={this.state} в FlatList, мы гарантируем, что сам FlatList будет повторно отображаться при изменении state.selected. Без установки этого prop FlatList не знал бы, что ему нужно повторно отображать какие-либо элементы, потому что это также PureComponent, и сравнение prop не покажет никаких изменений.
Комментарии:
1. Да, я тоже нашел это и добавил дополнительные данные, но это обновляет все мои кнопки. На этом мое понимание заканчивается, как мне обновить отдельных пользователей здесь?
2. Ну, это связано с самим setState, когда вы вызываете setState, он повторно отобразит весь компонент и обновит только те реквизиты, которые были изменены. если вы хотите обновить отдельные элементы (элемент списка), вы должны установить состояние всего списка, в вашем случае «DataSource», это вызовет повторный рендеринг компонента.