【问题标题】:How can I make componentDidMount render again?如何让 componentDidMount 再次渲染?
【发布时间】: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>
        )
    }

}

【问题讨论】:

    标签: reactjs react-native state react-props


    【解决方案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,这样它就知道它需要重新渲染。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-10
      相关资源
      最近更新 更多