如何让 componentDidMount 再次渲染?

Posted

技术标签:

【中文标题】如何让 componentDidMount 再次渲染?【英文标题】:How can I make componentDidMount render again? 【发布时间】:2020-04-15 13:14:11 【问题描述】:

我在探索组件中获取 api(makeup API) 并在探索按钮中使用它。 我将品牌作为 ExploreButtons 中的一个按钮。当我单击 ExploreButtons 的 FlatList 元素中的按钮时,我想在 ExploreButtons 的第二个 FlatList 中查看来自 api 的图像。当我单击按钮时,componentDidMount 是否可以重新呈现?

import React,  Component  from 'react'
import  View  from 'react-native'
import ExploreButtons from './ExploreButtons'

export default class Explore extends Component 
    constructor(props) 
        super(props);
        this.state = 
            isLoading: true,
            makeupApi: 'http://makeup-api.herokuapp.com/api/v1/products.json',
        
    
    callbackFunction = (item) => 
        this.setState(
            makeupApi: 'http://makeup-api.herokuapp.com/api/v1/products.json?brand=' + item,
        )
    

    async componentDidMount() 
        try 
            const response = await fetch(this.state.makeupApi);
            const responseJson = await response.json();
            this.setState(
                isLoading: false,
                dataSource: responseJson,
            , function () 
            );
            const reformattedArray = this.state.dataSource.map(obj => 
                var rObj = ;
                rObj = obj.brand;
                return rObj;
            );
            this.setState(
                duplicatesRemoved: reformattedArray.filter((item, index) => reformattedArray.indexOf(item) === index)
            )
        
        catch (error) 
            console.error(error);
        
    ;

    render() 
        console.log(this.state.makeupApi)
        return (
            <View style= flex: 1 >
                <ExploreButtons
                    api=this.state.dataSource
                    removedDuplicatesFromAPI=this.state.duplicatesRemoved
                    parentCallback=this.callbackFunction
                    makeupApi= this.state.makeupApi />
            </View>
        )
    




export default class ExploreButtons extends Component 

    getBrandImages = (item) => 
        this.props.parentCallback(item)
    

    render() 
        return (
            <View style= flex: 1 >
                <View>
                    <FlatList
                        horizontal
                        showsHorizontalScrollIndicator=false
                        data=this.props.removedDuplicatesFromAPI
                        renderItem=( item ) =>
                            <TouchableOpacity
                                style=styles.exploreButtons
                                onPress=() => 
                                    this.getBrandImages(item)
                                
                            >
                                <Text>item</Text>
                            </TouchableOpacity>
                        
                        keyExtractor=item => item
                    />
                </View>
                <View>
                    <FlatList
                        data=this.props.api
                        renderItem=( item ) =>
                            <View>
                                <Image source= uri: item.image_link 
                                    style=
                                        alignSelf: "center",
                                        width: '100%',
                                        height: 300,
                                     />
                            </View>
                        
                        keyExtractor=item => item.id.toString() />
                </View>
            </View>
        )
    


【问题讨论】:

【参考方案1】:

您可以将componentDidMount 中的所有逻辑放在另一个函数上,并在您调用回调时调用它。作为第一个非常粗略的方法,这将起作用:

注意:你并不真的需要状态中的API URL,将item放在状态上并基于它构造URL。

import React,  Component  from 'react';
import  View  from 'react-native';
import ExploreButtons from './ExploreButtons';

export default class Explore extends Component 
  API_URL = 'http://makeup-api.herokuapp.com/api/v1/products.json';

  constructor(props) 
    super(props);
    this.state = 
      isLoading: true,
      item: null,
      dataSource: null,
      duplicatesRemoved: [],
    ;
  

  getAPIURL(item) 
    if(!item)
      return API_URL
    
    return `$API_URL?brand=$item`;
  

  async fetchData(item) 
    try 
      const url = getAPIURL(item);
      const response = await fetch(url);
      const responseJson = await response.json();

      this.setState(
        isLoading: false,
        dataSource: responseJson,
        item,
      );

      const reformattedArray = responseJSON.map(( brand ) => brand);

      this.setState(
        duplicatesRemoved: reformattedArray.filter(
          (item, index) => reformattedArray.indexOf(item) === index,
        ),
      );
     catch (error) 
      console.error(error);
    
  

  async componentDidMount() 
    fetchData();
  

  render() 
    const  dataSource, duplicatesRemoved, item  = this.state;
    return (
      <View style= flex: 1 >
        <ExploreButtons
          api=dataSource
          removedDuplicatesFromAPI=duplicatesRemoved
          parentCallback=this.fetchData
          makeupApi=getURL(item)
        />
      </View>
    );
  


export default class ExploreButtons extends Component 
  getBrandImages = item => 
    this.props.parentCallback(item);
  ;

  render() 
    const  removedDuplicatesFromAPI, api  = this.props;

    return (
      <View style= flex: 1 >
        <View>
          <FlatList
            horizontal
            showsHorizontalScrollIndicator=false
            data=removedDuplicatesFromAPI
            renderItem=( item ) => (
              <TouchableOpacity
                style=styles.exploreButtons
                onPress=() => 
                  this.getBrandImages(item);
                
              >
                <Text>item</Text>
              </TouchableOpacity>
            )
            keyExtractor=item => item
          />
        </View>
        <View>
          <FlatList
            data=api
            renderItem=( item ) => (
              <View>
                <Image
                  source= uri: item.image_link 
                  style=
                    alignSelf: 'center',
                    width: '100%',
                    height: 300,
                  
                />
              </View>
            )
            keyExtractor=item => item.id.toString()
          />
        </View>
      </View>
    );
  


【讨论】:

它说可能未处理的 Promise Rejection (id: 0): ReferenceError: fetchData is not defined ReferenceError: fetchData is not defined 您需要在fetchData 之前添加await 和/或将其包装在try catch 块上 有item时返回Network request failed---- let url = !item ? this.API_URL : console.log(item);/* this.API_URL + '?brand=' + item */; 好吧,当有item时打印URL是什么,然后尝试调用API看看它返回什么。【参考方案2】:

如何让 componentDidMount 再次渲染?

不确定您的意思,但我认为您要问的是How can I make componentDidMount *run* again?,要做到这一点,您需要在callbackFunction 中使用相同的代码才能再次运行它。 componentDidMount 只会在组件第一次渲染后运行。

还要注意,如果你想重新渲染FlatList,你需要传递extraData,这样它就知道它需要重新渲染。

【讨论】:

以上是关于如何让 componentDidMount 再次渲染?的主要内容,如果未能解决你的问题,请参考以下文章

ReactJs:如何在渲染之前等待 componentDidMount() 完成?

如何更新 componentDidMount 中的上下文状态?

React Native this.setState() 仅在再次与组件交互后重新渲染

React Child componentDidMount不在Route上触发

axios在componentDidMount中获取数据后如何拍摄jest snapshot?

上下文提供程序中的 componentDidMount() 状态更改未触发子组件的重新渲染