Javascript 使用getDerivedStateFromProps获取API数据会导致组件多次渲染

Javascript 使用getDerivedStateFromProps获取API数据会导致组件多次渲染,javascript,reactjs,ecmascript-6,Javascript,Reactjs,Ecmascript 6,我正在尝试从API调用中获取一些数据。我正在使用getDerivedStateFromProps,componentDidMount,shouldcomonentupdate和componentdiddupdate` 我这样做是因为我需要userToken,它来自userToken:store.signnscreen.userToken,在调用函数getPassengerData之前到达那里,该函数需要userToken从API获取数据 这是整个组件: // imports class Hom

我正在尝试从API调用中获取一些数据。我正在使用
getDerivedStateFromProps
componentDidMount,
shouldcomonentupdate
componentdiddupdate`

我这样做是因为我需要
userToken
,它来自
userToken:store.signnscreen.userToken
,在调用函数
getPassengerData
之前到达那里,该函数需要
userToken
从API获取数据

这是整个组件:

// 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);
//导入
类主屏幕扩展组件{
静态导航选项={
标题:null,
};
状态={
错误:false,
};
静态getDerivedStateFromProps(props,状态){
if(props.userToken!==state.userToken){
返回{userToken:props.userToken};
}
返回null;
}
componentDidMount(){
这是.GetPassengersData();
}
shouldComponentUpdate(prevProps,状态){
返回this.props!==prevProps;
}
componentDidUpdate(prevProps、prevState){
const{error}=this.state;
如果(!错误){
这是.GetPassengersData();
}
}
GetPassengersData=async()=>{
const{passengersDataActionHandler,userToken}=this.props;
if(userToken&&userToken!==null){
试一试{
const response=等待获取(
'http://myAPI/public/api/getPassengers',
{
方法:“POST”,
标题:{
授权:`Bearer${userToken}`,
接受:'application/json',
“内容类型”:“应用程序/json”,
},
},
);
const responseJson=wait response.json();
if(has(responseJson,'error')){
this.setState({error:true});
Alert.Alert('错误','请检查您的凭据');
}否则{
passengersDataActionHandler(responseJson.success.data);
}
}捕获(错误){
this.setState({error:true});
警惕,警惕(
“错误”,
“您的请求出错,请稍后再试。”,
);
}
}
};
render(){
返回;
}
}
HomeScreen.defaultProps={
userToken:null,
};
主屏幕.propTypes={
导航:PropTypes.shape({}).isRequired,
passengersDataActionHandler:PropTypes.func.isRequired,
userToken:PropTypes.oneOfType([PropTypes.string]),
};
导出默认组合(
连接(
商店=>({
userToken:store.signnscreen.userToken,
乘客数据:store.homeScreen.passengersData,
}),
分派=>({
passengersDataActionHandler:token=>{
调度(passengersDataAction(令牌));
},
}),
),
)(主屏幕);
使用此实现,组件会多次渲染,因此会中断应用程序


我可能做错了什么?

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

其次,您需要仅在属性更改时触发componentDidUpdate中的API调用,而不是在没有检查的情况下直接触发,否则,API成功或错误中的setState将导致组件再次重新呈现调用
componentDidUpdate
,从而再次调用API,从而导致无限循环

第三,shouldComponentUpdate比较道具内部的检查并不完全正确,因为nestedObjects道具将给出假阴性结果,而且如果为道具编写深度相等性检查,如果状态更改,组件将不会重新渲染

// 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);
//导入
类主屏幕扩展组件{
静态导航选项={
标题:null,
};
状态={
错误:false,
};
componentDidMount(){
这是.GetPassengersData();
}
componentDidUpdate(prevProps、prevState){
if(prevProps.userToken!==此.props.userToken){
这是.GetPassengersData();
}
}
GetPassengersData=async()=>{
const{passengersDataActionHandler,userToken}=this.props;
if(userToken&&userToken!==null){
试一试{
const response=等待获取(
'http://myAPI/public/api/getPassengers',
{
方法:“POST”,
标题:{
授权:`Bearer${userToken}`,
接受:'application/json',
“内容类型”:“应用程序/json”,
},
},
);
const responseJson=wait response.json();
if(has(responseJson,'error')){
this.setState({error:true});
Alert.Alert('错误','请检查您的凭据');
}否则{
passengersDataActionHandler(responseJson.success.data);
}
}捕获(错误){
this.setState({error:true});
警惕,警惕(
“错误”,
“您的请求出错,请稍后再试。”,
);
}
}
};
render(){
返回;
}
}
HomeScreen.defaultProps={
userToken:null,
};
主屏幕.propTypes={
导航:PropTypes.shape({}).isRequired,
passengersDataActionHandler:PropTypes.func.isRequired,
userToken:PropTypes.oneOfType([PropTypes.string]),
};
导出默认组合(
连接(
商店=>({
userToken:store.signnscreen.userToken,
乘客数据:store.homeScreen.passengersData,
}),
分派=>({
passengersDataActionHandler:token=>{
调度(passengersDataAction(令牌));
},
}),
),
)(主屏幕);

您可以在
getPassengerData()
中设置状态。如果
状态
已更新,则将执行
组件更新()。这是inf循环。