重新渲染内部带有异步函数的组件

时间:2021-03-08 08:27:22

标签: javascript react-native

我是本机反应的新手,我的 JS 有点生疏。我需要能够更改 Firestore 收藏的价值。我有两个按钮可以通过设置状态来改变 typeOfPost 的值。 Component1 可以成功获取“this.state.typeOfPost”。但是,当我单击其中一个按钮并更新状态时,不会调用异步函数内的日志。它仅在应用程序最初呈现时调用。我觉得奇怪的是,我在 Component1 顶部的日志会按预期显示。有没有更好的方法来做到这一点?

class Forum extends Component {

 state = {
    typeOfPost: ' '
 }

 onPressSitter = () => {
    this.setState({
      typeOfPost: 'sitterPosts'
      })
 }


  onPressNeedSitter = () => {
    this.setState({
      typeOfPost: 'needPosts'
      })
 }


 render() {
    return (
      <View style={styles.container}>
        
        <View style={styles.row}>
            <TouchableOpacity
            style={styles.button}
            onPress={this.onPressSitter}
            >
            <Text>I am a sitter</Text>
            </TouchableOpacity>

            <TouchableOpacity
            style={styles.button}
            onPress={this.onPressNeedSitter}
            >
            <Text>Need a sitter</Text>
            </TouchableOpacity>

        </View>

        <View>
          <Component1 typeOfPost = {this.state.typeOfPost}> </Component1>
        </View>

      </View>
    )
  }
}

const Component1 = (props) => {
  console.log("type of post " + props.typeOfPost);
  const [loading, setLoading] = useState(true); // Set loading to true on component mount
  const [data, setData] = useState([]); // Initial empty array of data
  const getData = async () => {
    console.log("type of post inside async " + props.typeOfPost);
    const subscriber = firestore()
    .collection(props.typeOfPost) // need to be able to update this
    .onSnapshot(querySnapshot => {
      const data = [];

      querySnapshot.forEach(documentSnapshot => {
        data.push({
          ...documentSnapshot.data(),
          key: documentSnapshot.id,
        });
      });

      setData(data);
      setLoading(false);
    });

    // Unsubscribe from events when no longer in use
    return () => subscriber();
  }

  useEffect(() => {
    getData();
  }, [])

  if (loading) {
    return <ActivityIndicator />;
  }

  return (
      <FlatList
      data={data}
      ListEmptyComponent={
          <View style={styles.flatListEmpty}>
              <Text style={{ fontWeight: 'bold' }}>No Data</Text>
          </View>
      }
      renderItem={({ item }) => (
          <View>
            <Text>User ID: {item.fullName}</Text>
          </View>
      )}
  />
  )
}


2 个答案:

答案 0 :(得分:1)

mountrender 之间存在差异。除了我所做的一些评论外,我认为您的代码没有问题。问题是,当您更改 typeOfPost 时,会重新渲染组件,但不会再次调用 useEffect,因为您说的是,它只是在第一次挂载时才调用:

useEffect(() => {

}, []) // ---> [] says to run only when first mounted

但是在这里,您希望它在 typeOfPost 更改时运行。因此,您可以这样做:

useEffect(() => {
    getData();
  }, [typeofPost])
class Forum extends Component {

 state = {
    typeOfPost: ' '
 }

 onPressSitter = () => {
    this.setState({
      typeOfPost: 'sitterPosts'
      })
 }


  onPressNeedSitter = () => {
    this.setState({
      typeOfPost: 'needPosts'
      })
 }


 render() {
    return (
      <View style={styles.container}>
        
        <View style={styles.row}>
            <TouchableOpacity
            style={styles.button}
            onPress={this.onPressSitter}
            >
            <Text>I am a sitter</Text>
            </TouchableOpacity>

            <TouchableOpacity
            style={styles.button}
            onPress={this.onPressNeedSitter}
            >
            <Text>Need a sitter</Text>
            </TouchableOpacity>

        </View>

        <View>
          <Component1 typeOfPost = {this.state.typeOfPost}> </Component1>
        </View>

      </View>
    )
  }
}

const Component1 = (props) => {
  const { typeOfPost } = props 
  console.log("type of post " + props.typeOfPost);
  const [loading, setLoading] = useState(true); // Set loading to true on component mount
  const [data, setData] = useState([]); // Initial empty array of data
  const getData = () => {
    setLoading(true)
    console.log("type of post inside async " + props.typeOfPost);
    const subscriber = firestore()
    .collection(props.typeOfPost) // need to be able to update this
    .onSnapshot(querySnapshot => {
      const data = [];

      querySnapshot.forEach(documentSnapshot => {
        data.push({
          ...documentSnapshot.data(),
          key: documentSnapshot.id,
        });
      });

      setData(data);
      setLoading(false);
    });

    // Unsubscribe from events when no longer in use
    return () => subscriber();
  }

  useEffect(() => {
    getData();
  }, [typeofPost])

  if (loading) {
    return <ActivityIndicator />;
  }

  return (
      <FlatList
      data={data}
      ListEmptyComponent={
          <View style={styles.flatListEmpty}>
              <Text style={{ fontWeight: 'bold' }}>No Data</Text>
          </View>
      }
      renderItem={({ item }) => (
          <View>
            <Text>User ID: {item.fullName}</Text>
          </View>
      )}
  />
  )
}

答案 1 :(得分:0)

  1. 您正在使用基于类的组件来访问 react hook,这是一种不好的做法,我建议您使用功能组件,并且您可以访问 react useCallback hook,它可以轻松处理您的请求
const ButtonPressed = useCallback(() => {
        setLoading(true);
        getData()
        }).then(() => setLoading(false));
    }, [loading]);
相关问题