为什么在this.setState()完成状态设置之前渲染组件?

时间:2019-01-19 04:08:37

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

我正在构建我的第一个React本机应用程序。我正在使用Firebase,Redux和React Native来构建我的应用程序。

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

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

我认为在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)```

2 个答案:

答案 0 :(得分:2)

这是因为setState操作是异步的,并且为了提高性能而进行了批处理。在setState的文档中对此进行了解释。

  

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

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

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

答案 1 :(得分:0)

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(全局状态),所以不必将其添加到本地状态。您可以通过道具直接访问房间的价值。