当我想显示来自 API 的数据时出错

error when I want to display data from an API

在我尝试放置的屏幕中。我得到了产品的 ID。上一个屏幕是来自 API 的产品列表。感谢 props.data 我得到了这个 ID console.log ('props', this.props.data) 工作正常并且 returns 对我来说是正确的 ID,无论点击的是什么产品。 有了这个产品的ID,我想找到这个产品的详细信息(参考,系列,价格,库存等)。 我创建了这个函数来通过我的 API.

调用产品详细信息
initListData = async () => {
    if (parseInt(this.state.productId) > 0) {
      let product_data = await getProduct(this.state.productId);

      console.log('product_data', product_data)

      this.setState({
        displayArray: product_data,
        loadMoreVisible: (product_data.length >= 15 ? true : false),
        currentPage: 2
      });
    }
  };

我认为问题是 displayArray[] 是空的所以

let product_data = await getProduct(this.state.productId);

无效。

我收到此错误:无法从不同组件的函数体内部更新组件 你能给我解释一下这是怎么回事吗?

完整代码

export default class Information extends Component {
  constructor(props) {
    super(props);
    this.state = {
      productId: this.props.data,
      displayArray: [],
    }
    console.log('props', this.props.data) // ok, ça fonctionne, on récupère bien l'ID du produit cliqué
  };

  initListData = async () => {
    if (parseInt(this.state.productId) > 0) {
      let product_data = await getProduct(this.state.productId);

      console.log('product_data', product_data)

      this.setState({
        displayArray: product_data,
        loadMoreVisible: (product_data.length >= 15 ? true : false),
        currentPage: 2
      });
    }
  };

  async UNSAFE_componentWillMount() {
    this.initListData();
  }

  render() {
    console.log('ça c\'est data = ', this.props.data );
    console.log('ça c\'est les props =', this.props );
    console.log('ça c\'est le state = ', this.state );
    
    return (
      <ScrollView contentContainerStyle={{flex: 1}}>
        {
          this.state.displayArray.map((item, i) => (
            <ListItem bottomDivider>
                <Icon name='flight-takeoff' />
                <ListItem.Content>
                <ListItem.Title style={{color: '#d35400'}}>{item.name}</ListItem.Title>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.family")}: {item.family_id}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.reference")}: {item.reference}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.id")}: {item.id}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.cost")}: {item.cost}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.description")}: {item.description}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.stock")}: {item.stock_status}
                </ListItem.Subtitle>
                </ListItem.Content>
            </ListItem>
          ))
        }
      </ScrollView>
      );
    }
  }

getProduct 函数:[我只需要隐藏真实的 url]

export async function getProduct(product_id) {
  const abortController = new AbortController();

  let user_id = await retrieveProfileUserId();
  let lang = await retrieveAppLang();
  let access_token = await renewAccessToken();
  let result = {};

  if (parseInt(product_id) > 0 && access_token != '' && parseInt(user_id) > 0) {
    try {
      let response = await fetch(
          API_URL +
          "/products/" + product_id +
          "?user_id=" + user_id +
          "&society_id=" + API_SOCIETYID +
          "&access_token=" + access_token +
          "&lang=" + lang,
        {
          method: "GET",
          signal: abortController.signal,
          headers: {
            Accept: "application/json",
            "Content-Type": "application/json",
            Authorization: "Bearer " + API_SECRETKEY,
            "Cache-Control": "no-cache, no-store, must-revalidate",
            Pragma: "no-cache",
            Expires: "0"
          }
        }
      )
      .then(response => response.json())
      .then(responseData => {
        if (responseData.status == 200 && responseData.data) {
          console.log("getProduct()::success", responseData.data);
          result = responseData.data;
        } else if (
          responseData.status >= 200 && responseData.status <= 404 &&
          responseData.data.error && responseData.data.error.length >= 3
        ) {
          // Handle error
          throw responseData.data.error;
        } else {
          throw "error";
        }
      });
    } catch (error) {
      //console.log(error);
     abortController.abort();
    }
  }

尝试改变一些东西,它应该会起作用。

我也不喜欢直接在fn里面设置state,所以我提出如下修改:

initListData = async () => {
    if (this.props.data != null) {
      const productData = await getProduct(this.state.productId);

      return productData; // You are missing this, this is vital!
    }
  };

  async componentDidMount() {
    const data = await this.initListData(); // don't forget await here if you're using async
    if (data.id) {
      this.setState((prevState) => ({
        displayArray: [...prevState.displayArray, data],
        loadMoreVisible: ..., // I don't know what do you want here, because again, you receive an object from your backend, not an array.
        currentPage: 2
      }));
    }
  }

为了确保这一点很清楚,我 post 一个答案来显示我现在拥有的代码。 我希望我正确理解了康斯坦丁先生的解释,如果不是这样,我深表歉意,我按照你向我建议的 initListData 和 componentWillUnMount 进行了修改,但我的印象是我们没有输入 componentDidMount,displayArray 是空的。 在终端我的 console.log 给出:

props 16 this is displayArray = Array []

我没有 console.log('productData=', productData)

我收到 3 个黄色错误:

[Unhandled promise rejection: ReferenceError: Can't find variable: productData]

[Unhandled promise rejection: TypeError: this.initListData is not a function. (In 'this.initListData()', 'this.initListData' is undefined)

[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'data.length')]

export default class Information extends Component {
  constructor(props) {
    super(props);
    this.state = {
      productId: this.props.data,
      displayArray: [],
    }
    console.log('props', this.props.data) // ok, ça fonctionne, on récupère bien l'ID du produit cliqué
  };

  initListData = async () => {
    if (this.props.data != null) {
      console.log('this.props.data =', this.props.data) // OK 
      const productData = await getProduct(this.state.productId);
    }    
  };

  

  async componentDidMount() {
    console.log('productData=', productData)
    const data = await this.initListData(); // don't forget await here if you're using async
    console.log('data', data)
    if (data.length) {
      this.setState({
        displayArray: data,
        loadMoreVisible: data.length >= 15, // no need for ternary
        currentPage: 2
      });
    }
  }

  render() {
    console.log('this is displayArray = ', this.state.displayArray );
       
    return (
      <ScrollView contentContainerStyle={{flex: 1}}>
        {
          this.state.displayArray.map((item, i) => (
            <ListItem bottomDivider>
                <Icon name='flight-takeoff' />
                <ListItem.Content>
                <ListItem.Title style={{color: '#d35400'}}>{item.name}</ListItem.Title>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.family")}: {item.family_id}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.reference")}: {item.reference}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.id")}: {item.id}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.cost")}: {item.cost}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.description")}: {item.description}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.stock")}: {item.stock_status}
                </ListItem.Subtitle>
                </ListItem.Content>
            </ListItem>
          ))
        }
      </ScrollView>
      );
    }
  }

------------------------编辑---------------- ----------

修改后:

export default class Information extends Component {
  constructor(props) {
    super(props);
    this.state = {
      productId: this.props.data,
      displayArray: [],
    }
    console.log('props', this.props.data) // ok, ça fonctionne, on récupère bien l'ID du produit cliqué
  };

  initListData = async () => {
    if (this.props.data != null) {
      console.log('this.props.data =', this.props.data) // OK 
      let productData = await getProduct(this.props.data);
      console.log('productData =', productData )
    }    
  };

  

  async componentDidMount() {
    const data = await this.initListData(); // don't forget await here if you're using async
    console.log('data', data)
    if (data.length) {
      this.setState({
        displayArray: data,
        loadMoreVisible: data.length >= 15, // no need for ternary
        currentPage: 2
      });
    }
    return data;
  }
  

  render() {
    console.log('this is displayArray = ', this.state.displayArray);
       
    return (
      <ScrollView contentContainerStyle={{flex: 1}}>
        {
          this.state.displayArray.map((item, i) => (
            <ListItem bottomDivider>
                <Icon name='flight-takeoff' />
                <ListItem.Content>
                <ListItem.Title style={{color: '#d35400'}}>{item.name}</ListItem.Title>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.family")}: {item.family_id}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.reference")}: {item.reference}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.id")}: {item.id}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.cost")}: {item.cost}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.description")}: {item.description}
                </ListItem.Subtitle>
                <ListItem.Subtitle style={{ color: '#F78400' }}>
                        {i18n.t("information.stock")}: {item.stock_status}
                </ListItem.Subtitle>
                </ListItem.Content>
            </ListItem>
          ))
        }
      </ScrollView>
      );
    }
  }

在控制台中:

this is displayArray = Array []

productData = Object { "cost": 1.86, "created_at": "2018-05-17T21:27:22Z", "custom_fields": Array [], "description": "", "family_id": 1, "id": 16, "incl_tax": 1, "is_visible": 1, "name": "", "photo": Object { "1": Object { "id": 1, "order": 1, "title_fr": "tomato-ketchup-flacon-souple", "url": "/i/p-6-1-6-146_5844_16_1.jpg", }, }, "quantity": "0", "reference": "", "stock_status": "0", "tax_rate_id": 1, "unit": "", "updated_at": "2018-05-17T21:27:24Z", "weight": 0, }

data undefined

错误:

[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'data.length')]

空白页