在React中可见时,在Modal中调用API的正确方法是什么?

时间:2019-04-14 08:46:14

标签: reactjs react-native

假设我在组件内部有一个模态,并且想在单击某些按钮时显示模态:

render(){
  ...
  <Modal 
   is={this.state.productId} 
   visilble={this.state.visible} 
  />
}

在模态组件内部,我想调用API以基于选定的ID获取产品详细信息,如下所示:

 componentWillReceiveProps(nextProps) {
    if(nextProps.visible && !this.props.visible) {
      fetch(...).then(res => {
        this.setState({
          product: res.data
        })
      }).catch(err => {
        ...
      })
    }
  }

React docs中说,不赞成componentWillReceiveProps,componentWillUpdate,您应该在新代码中避免使用它们。因此,我尝试使用静态getDerivedStateFromProps()

static getDerivedStateFromProps()(nextProps) {
  if(nextProps.visible && ...) {
    fetch(...).then(res => {
      return {
       product: res.data
      }
    }).catch(err => {
      ...
    })
   } else return null (or just return null here without else)
}

上面的代码不起作用,因为fetch是异步的,因此它总是返回null或不返回任何东西,您不能在这里使用await来等待api也解决,而且我听说getDerivedStateFromProps不应该用于数据提取。

那么解决问题的最佳方法是什么?

5 个答案:

答案 0 :(得分:0)

我认为最好决定是否在父组件中显示Modal组件,因为Modal组件应该是仅呈现与模态相关的视图的功能组件。这样,每次Modal组件都不会被渲染,只有在visible标志为true时才会被渲染。

{ this.state.visible &&
  <Modal />
}

在父组件中,如果仅在需要初始渲染后才需要获取数据,则可以在componentDidMount中获取数据;如果在每次更新后需要模态获取数据,则可以在componentDidUpdate中获取数据。提取数据集后,可见状态为true。

快乐编码!

答案 1 :(得分:0)

您可以基于Modal来安装this.state.visible并在componentDidMount上安装Modal或通过componentDidUpdate改变道具时开始获取。

// delay
const delay = () => new Promise(res => setTimeout(res, 1000));

// fake products
const products = [
  { id: 1, text: "product 1" },
  { id: 2, text: "product 2" },
  { id: 3, text: "product 3" }
];

// fake ajax call
const API = async productId => {
  await delay();
  return products.find(p => p.id === productId);
};

class Parent extends Component {
  state = { productId: 1, visible: false };

  toggleShow = () => {
    this.setState(prevState => ({ visible: !prevState.visible }));
  };

  setProductId = productId => this.setState({ productId, visible: true });

  render() {
    return (
      <div className="App">
        <button onClick={this.toggleShow}>show or hide</button>
        <button onClick={() => this.setProductId(1)}>fetch product 1</button>
        <button onClick={() => this.setProductId(2)}>fetch product 2</button>
        <button onClick={() => this.setProductId(3)}>fetch product 3</button>
        <button onClick={() => this.setProductId(4)}>unknown product id</button>
        {this.state.visible && <Modal is={this.state.productId} />}
      </div>
    );
  }
}

class Modal extends Component {
  state = { product: null, fetching: false };

  componentDidMount = () => {
    this.fetchProduct();
  };

  componentDidUpdate = prevProps => {
    if (prevProps.is !== this.props.is) {
      this.fetchProduct();
    }
  };

  fetchProduct = async () => {
    this.setState({ fetching: true });
    const product = await API(this.props.is);
    this.setState({ product, fetching: false });
  };

  render() {
    const { product, fetching } = this.state;

    if (fetching) return <h1>{`fetching product ${this.props.is}`}</h1>;

    return product ? (
      <div>
        <h1>{`product id: ${product.id}`}</h1>
        <h3>{`text: ${product.text}`}</h3>
      </div>
    ) : (
      <h1>Product not found</h1>
    );
  }
}

SandBox

答案 2 :(得分:0)

实际上,您可以在另一种 pureComponent 中使用<modal/> (例如:componentContainer),只需在主视图中调用它即可。并仅在主视图状态内使用一个对象作为<componentContainer/>数据作用域,并将其作为此代码的属性提供

  construcor(prop){
        super(props);
         this.state={
          productDetail:null<<change this in data fetch
          }
   }
<componentContainer data={this.state.productDetail} modalVisible={this.state.changeNumderModal}/>

并在组件容器内:

     <Modal
            animationType="fade"
            transparent={true}
            visible={this.props.modalVisible}//<<<<<<<<<
            onRequestClose={() => {

            }}>
                    //contents:
                     this.props.data.map(()=>//-----)
            </View>
        </Modal>

在这种方法中,您只有一个模式和一个作用域作为其数据,您可以在主组件中调用 fetch 和其他函数,其他函数也可以...如果需要,您可以甚至将功能属性传递给模式容器:

   someFunction(someval){
      //do some thing  
      }

    <componentContainer data={this.state.productDetail} modalVisible={this.state.changeNumderModal} someFunction={(val)=>this.someFunction(val)}/>

并在 中调用它:

          this.props.someFunction('what ever you want')

答案 3 :(得分:0)

所以让我们假设您已经通过单击按钮完成了模态的隐藏和显示,现在只要打开模型 在componentWillMount函数内部

class Modal extends Component {

  this.state = {product:[], loader : false}

  componentWillMount(){
    fetch(...).then(res => {
     this.setState({
       product: res.data
     })
    }).catch(err => {
      ...
    })
  }

  render(){
    const {product, loader} = this.state;
    return (
      if (loader) return <ProductComponent data = {product}/> 
      else return <div> No data found </div>
    );
  }

}

答案 4 :(得分:0)

您可以使用以下方法:

componentDidUpdate(prevProps, prevState, snapshot) {
    if (this.props.visible && !prevProps.visible) {
        // make the API call here
    }
}