【问题标题】:Understanding React Natives setState and componentWillMount from FlatList从 FlatList 理解 React Native 的 setState 和 componentWillMount
【发布时间】:2019-03-08 12:55:42
【问题描述】:

所以我正在尝试使用 expo 和 expo 音频制作一个简单的应用程序,它将生成音频按钮和文本列表。但我无法弄清楚在重绘 setState OUTSIDE 组件WillMount 以及如何使用新 URI 重新制作声音对象方面反应如何工作

所以现在它可以工作,但只播放 FIRST uri,我认为这是因为该对象仍然存在。

而且它不会改变按钮的状态,我知道这是因为 react 无法从 FlatList 中看到它的变化

如果我只在渲染视图中创建一个按钮,它可以在它之外工作。

如果我使用 LegacyImplementation=true ,FlatList 将呈现 setStates .. 但我警告说这已被弃用。它同时为所有按钮呈现它

这是我的处理程序类:

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 && this.state.playingStatus !== "playing") {
      this.setState({ playingStatus: "playing" });
    } else if (!status.isPlaying && 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>
    );

  }
}

更新:在 flatlist 中设置 extraData={this.state} 会更新按钮。但所有按钮。如何更改按钮的范围?

【问题讨论】:

  • 你的意思是说每一行应该独立运行,即暂停,播放应该独立于FlatList中的每个项目?

标签: reactjs react-native expo


【解决方案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】:

    我查看了here 的文档,我发现只要你传递了 state 属性,它就会重新渲染,请参阅以下解释:

    通过将 extraData={this.state} 传递给 FlatList,我们确保 FlatList 本身会在 state.selected 更改时重新渲染。如果不设置此 prop,FlatList 将不知道它需要重新渲染任何项目,因为它也是一个 PureComponent,并且 prop 比较不会显示任何更改。

    【讨论】:

    • 是的,也发现了这个并添加了 extraData,但它更新了我所有的按钮。这是我的理解停止的地方,我如何在这里更新个人?
    • 嗯,它与 setState 本身有关,当您调用 setState 时,它​​会重新渲染整个组件,并且只会更新已更改的道具。如果您想更新个人(列表的一项),您必须设置整个列表的状态,在您的情况下为“dataSource”,这将触发组件的重新渲染。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 2023-02-22
    • 1970-01-01
    • 2018-04-05
    • 2018-06-04
    • 1970-01-01
    相关资源
    最近更新 更多