从异步函数准备好数据后重新渲染

时间:2019-12-06 10:59:01

标签: reactjs react-native

我有一个异步功能,该功能可以从网络上获取笔记,但我遇到的问题是它试图呈现一个空数据数组,因此我收到此错误,说item.id为undefined,因为数组为空。我尝试放置条件if (data.length === 0) return <Text>No Entries</Text>,但是即使我console.log(data)可以看到数据已经到达,它也不会重新呈现任何内容。数据到达后,是否有任何其他方式可以渲染?

export default class NoteList extends Component {
  render() {
    const { data} = this.props;
    return (
      <View style={styles.cardView}>
        <FlatList
          numColons={data.length}
          data={data}
          renderItem={({ item: { name, content, id } }) => {
            return (
              <View>
                <NoteCard 
                  name={name}
                  content={content}
                />
              </View>
            );
          }}
          keyExtractor={(item) => item.id}
        />
      </View>
    );
  }
}

如何防止这种情况:

TypeError: TypeError: undefined is not an object (evaluating 'item.id')

我也收到此错误,但我认为这与管理第一个问题有关。

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory 
leak in your application. To fix, cancel all subscriptions and asynchronous tasks in %s.%s, the componentWillUnmount method,

2 个答案:

答案 0 :(得分:1)

您遇到的问题在于,父级将数据保存在状态中。因此,您会收到有关更新已卸载组件状态的警告。有很多不同的方法可以解决此问题。我喜欢的一种方式(由于可读性)是在组件安装时使用变量。一个简单的例子:

class News extends Component {
  _isMounted = false;
  constructor(props) {
    super(props);
    this.state = {
      news: [],
    };
  }
  componentDidMount() {
    this._isMounted = true;
    axios
      .get('https://hn.algolia.com/api/v1/search?query=react')
      .then(result => {
        if (this._isMounted) {
          this.setState({
            news: result.data.hits,
          });
        }
      });
  }
  componentWillUnmount() {
    this._isMounted = false;
  }
  render() {
    ...
  }
}

现在,设置数据后,NoteList组件将自动更新。但是,api调用失败时会发生什么。为了防止陈旧的数据,我喜欢使用条件渲染。就像您建议的那样:

export default class NoteList extends Component {
  render() {
    const { data } = this.props;

    if (data) {
      return (
        <View style={styles.cardView}>
          <FlatList
            numColons={data.length}
            data={data}
            renderItem={({ item: { name, content, id } }) => {
              return (
                <View>
                  <NoteCard name={name} content={content} />
                </View>
              );
            }}
            keyExtractor={item => item.id}
          />
        </View>
      );
    }
  }
}

答案 1 :(得分:0)

在React中执行此操作的常用方法是跟踪何时获取数据。这可以例如完成通过在您的状态下添加一个isFetching字段:

// This would be your default state
this.state = {
  isFetching: false
};

然后,当您触发请求时(最好在componentDidMount中),您可以使用以下方式将isFetching设置为true:

this.setState({ isFetching: true });

最后,当数据到达时,再次将其设置为false:

this.setState({ isFetching: false });

现在,在渲染功能中,您可以执行以下操作:

render () {
 return (
    <div className="something">
      <h3>Some content</h3>
      {this.state.isFetching ? <LoadingComponent /> : (
         <ul>
           {listItems}
         </ul>
      )}
    </div> 
  )
}

通过使用状态,您不必担心告诉组件做点什么,它会对状态的变化做出反应并相应地进行渲染。