【问题标题】:Why is component rendering before this.setState() has finished setting the state?为什么组件在 this.setState() 设置完成之前渲染?
【发布时间】:2019-01-19 04:08:36
【问题描述】:

我正在构建我的第一个 react 原生应用。我正在使用 Firebase、Redux 和 React Native 来构建我的应用程序。

我正在使用 thunk 从我的数据库中获取数据,并且我想使用该数据设置我的组件的本地状态。

当我在渲染函数中使用 console.log(this.props.room) 时,我可以看到我的数据库中的数据,但它没有被添加到 componentDidMount() 中的本地状态,所以我知道我的 thunk 和后端是正常工作。

我认为我的组件在 componentDidMount 函数中设置本地状态之前正在渲染。有没有办法在 this.setState() 运行时阻止它渲染?我的代码如下。还是 this.setState 不起作用的其他原因?

import { connect } from 'react-redux';
import {
  Image,
  Platform,
  ScrollView,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
  TextInput
} from 'react-native';

import { submitIdea, getRoom } from '../redux/reducers/rooms/actions'
class RoomScreen extends React.Component {
  static navigationOptions = {
    title: 'Undecided!'
  };
  constructor(props) {
    super(props)
    this.state = {
      currentUser: '',
      submittedIdea: false,
      currentUserIdea: '',
      roomName: '',
      ownerName: '',
      peopleAndIdeas: [],
      prompt: '',
      room: {}
    }
    this.handleIdeaSubmit = this.handleIdeaSubmit.bind(this)
  }

  handleIdeaSubmit() {
    const { user, roomName } = this.props.navigation.state.params
    this.setState({ submittedIdea: true })
    this.props.submitIdea(user, this.state.userIdea, roomName)
  }

  async componentDidMount() {
    const { user, roomName } = this.props.navigation.state.params
    await this.props.getRoom(roomName)
    this.setState({
      room: this.props.room
    })
  }

  render() {
    return (
      <View style={styles.container}>

        <ScrollView contentContainerStyle={styles.contentContainer}>
          <View>
            <Text>Room name: {this.state.room.name}</Text>
          </View>
          <View>
            <Text>This room was created by: {this.state.room.owner}</Text>
          </View>
          <View>
            <Text>What are we deciding? {this.state.room.prompt}</Text>
          </View>

          {/* checking whether or not the user has submitted an idea and altering the view */}

          {!this.state.submittedIdea ?

            <View style={styles.container}>
              <TextInput
                style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
                onChangeText={(text) => this.setState({ userIdea: text })}
                value={this.state.createRoomName}
                placeholder="Enter your idea."
              />
              <TouchableOpacity
                style={styles.button}
                onPress={this.handleIdeaSubmit}
              >
                <Text> Submit Idea. </Text>
              </TouchableOpacity>
            </View> :
            <View>
              <Text>Your idea was: {this.props.userIdea}</Text>
            </View>
          }

          <View style={styles.getStartedContainer}>
            <Text>IDEAS</Text>
          </View>

          <View>
            <Text style={styles.getStartedText}>USERS</Text>
          </View>

        </ScrollView>
      </View >
    );
  }
}

const mapStateToProps = state => ({
  room: state.room.room
})

const mapDispatchToProps = (dispatch) => ({
  getRoom: (roomName) => dispatch(getRoom(roomName)),
  submitIdea: (user, idea, roomName) => dispatch(submitIdea(user, idea, roomName))
})

export default connect(mapStateToProps, mapDispatchToProps)(RoomScreen)```

【问题讨论】:

    标签: javascript firebase react-native redux redux-thunk


    【解决方案1】:

    这是因为 setState 操作是异步的,并且是批处理以提高性能。这在 setState 的文档中有解释。

    setState() 不会立即改变 this.state 而是创建一个 等待状态转换。调用 this 后访问 this.state 方法可能会返回现有值。没有 保证对 setState 的调用和调用的同步操作可能 进行批处理以获得性能提升。

    所以你可以做这样的事情,

    this.setState({foo: 'bar'}, () => { 
    // Do something here. 
    });
    

    【讨论】:

    • 我没有意识到 setState 是异步的。谢谢!
    • 欢迎您!所以你知道你可以等待 this.setState()
    【解决方案2】:
    async componentDidMount() {
      const { user, roomName } = this.props.navigation.state.params
      await this.props.getRoom(roomName)
      this.setState({
        room: this.props.room
      })
    }
    

    在这种情况下,您不必使用本地状态。

     render() {
     const {room: {name}} = this.props;
    
     return (
      <View style={styles.container}>
        <ScrollView contentContainerStyle={styles.contentContainer}>
          <View>
            <Text>Room name: {name}</Text>
          </View>
       </ScrollView>
      </View>
      )
     }
    

    由于您使用的是 redux(全局状态),因此您不必在本地状态中添加它。您可以直接从道具中获取房间的价值。

    【讨论】:

    • 谢谢,这行得通!不确定我为什么要尝试使用本地状态。
    猜你喜欢
    • 2018-09-19
    • 1970-01-01
    • 2021-05-18
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    • 2017-04-04
    相关资源
    最近更新 更多