代码之家  ›  专栏  ›  技术社区  ›  Non

使用getDerivedStateFromProps获取API数据会导致组件多次呈现

  •  0
  • Non  · 技术社区  · 5 年前

    我正试图从一个API调用中获取一些数据。我在用 getDerivedStateFromProps , componentDidMount, shouldComponentUpdate and componentDidUpdate`。

    我这样做是因为我需要 userToken 它来自 userToken: store.signinScreen.userToken GetPassengersData 需要 用户令牌

    这是整个组件:

    // imports
    
    class HomeScreen extends Component {
      static navigationOptions = {
        header: null,
      };
    
      state = {
        error: false,
      };
    
      static getDerivedStateFromProps(props, state) {
        if (props.userToken !== state.userToken) {
          return { userToken: props.userToken };
        }
        return null;
      }
    
      componentDidMount() {
        this.GetPassengersData();
      }
    
      shouldComponentUpdate(prevProps, state) {
        return this.props !== prevProps;
      }
    
      componentDidUpdate(prevProps, prevState) {
        const { error } = this.state;
        if (!error) {
          this.GetPassengersData();
        }
      }
    
      GetPassengersData = async () => {
        const { passengersDataActionHandler, userToken } = this.props;
        if (userToken && userToken !== null) {
          try {
            const response = await fetch(
              'http://myAPI/public/api/getPassengers',
              {
                method: 'POST',
                headers: {
                  Authorization: `Bearer ${userToken}`,
                  Accept: 'application/json',
                  'Content-Type': 'application/json',
                },
              },
            );
            const responseJson = await response.json();
            if (has(responseJson, 'error')) {
              this.setState({ error: true });
              Alert.alert('Error', 'Please check your credentials.');
            } else {
              passengersDataActionHandler(responseJson.success.data);
            }
          } catch (error) {
            this.setState({ error: true });
            Alert.alert(
              'Error',
              'There was an error with your request, please try again later.',
            );
          }
        }
      };
    
      render() {
        return <TabView style={styles.container} />;
      }
    }
    
    HomeScreen.defaultProps = {
      userToken: null,
    };
    
    HomeScreen.propTypes = {
      navigation: PropTypes.shape({}).isRequired,
      passengersDataActionHandler: PropTypes.func.isRequired,
      userToken: PropTypes.oneOfType([PropTypes.string]),
    };
    
    export default compose(
      connect(
        store => ({
          userToken: store.signinScreen.userToken,
          passengersData: store.homeScreen.passengersData,
        }),
        dispatch => ({
          passengersDataActionHandler: token => {
            dispatch(passengersDataAction(token));
          },
        }),
      ),
    )(HomeScreen);
    

    我会做错什么?

    0 回复  |  直到 5 年前
        1
  •  1
  •   Shubham Khatri    5 年前

    首先你不需要储存 userToken 在状态中,因为您不在本地修改它,因此不需要 getDerivedStateFromProps

    componentDidUpdate 因此再次调用API会导致无限循环

    第三,shouldComponentUpdate比较props中的检查不完全正确,因为nestedObjects props将给出一个假阴性结果,而且如果您为props编写一个深度相等检查,则如果状态更改,组件将不会重新呈现。

    // imports
    
    class HomeScreen extends Component {
      static navigationOptions = {
        header: null,
      };
    
      state = {
        error: false,
      };
    
      componentDidMount() {
        this.GetPassengersData();
      }
    
      componentDidUpdate(prevProps, prevState) {
        if (prevProps.userToken !== this.props.userToken) {
          this.GetPassengersData();
        }
      }
    
      GetPassengersData = async () => {
        const { passengersDataActionHandler, userToken } = this.props;
        if (userToken && userToken !== null) {
          try {
            const response = await fetch(
              'http://myAPI/public/api/getPassengers',
              {
                method: 'POST',
                headers: {
                  Authorization: `Bearer ${userToken}`,
                  Accept: 'application/json',
                  'Content-Type': 'application/json',
                },
              },
            );
            const responseJson = await response.json();
            if (has(responseJson, 'error')) {
              this.setState({ error: true });
              Alert.alert('Error', 'Please check your credentials.');
            } else {
              passengersDataActionHandler(responseJson.success.data);
            }
          } catch (error) {
            this.setState({ error: true });
            Alert.alert(
              'Error',
              'There was an error with your request, please try again later.',
            );
          }
        }
      };
    
      render() {
        return <TabView style={styles.container} />;
      }
    }
    
    HomeScreen.defaultProps = {
      userToken: null,
    };
    
    HomeScreen.propTypes = {
      navigation: PropTypes.shape({}).isRequired,
      passengersDataActionHandler: PropTypes.func.isRequired,
      userToken: PropTypes.oneOfType([PropTypes.string]),
    };
    
    export default compose(
      connect(
        store => ({
          userToken: store.signinScreen.userToken,
          passengersData: store.homeScreen.passengersData,
        }),
        dispatch => ({
          passengersDataActionHandler: token => {
            dispatch(passengersDataAction(token));
          },
        }),
      ),
    )(HomeScreen);