#reactjs #react-native
#reactjs #react-native
Вопрос:
Предположим, что у меня есть модал внутри компонента, и я хочу показывать модал при нажатии некоторых кнопок:
render(){
...
<Modal
is={this.state.productId}
visilble={this.state.visible}
/>
}
Внутри модального компонента я хочу вызвать API для получения сведений о продукте на основе выбранного идентификатора следующим образом:
componentWillReceiveProps(nextProps) {
if(nextProps.visible amp;amp; !this.props.visible) {
fetch(...).then(res => {
this.setState({
product: res.data
})
}).catch(err => {
...
})
}
}
В документах React говорится, что componentWillReceiveProps, componentWillUpdate устарели, и вам следует избегать их в новом коде.Поэтому я пытаюсь использовать статический getDerivedStateFromProps()
static getDerivedStateFromProps()(nextProps) {
if(nextProps.visible amp;amp; ...) {
fetch(...).then(res => {
return {
product: res.data
}
}).catch(err => {
...
})
} else return null (or just return null here without else)
}
Приведенный выше код не работает, поскольку выборка является асинхронной, поэтому она всегда возвращает null или ничего не возвращает, вы не можете использовать await здесь, чтобы дождаться разрешения API, и я слышал, что getDerivedStateFromProps не следует использовать для выборки данных.
Итак, каков наилучший способ решения проблемы?
Ответ №1:
Я думаю, лучше решить, показывать ли модальный компонент или нет в родительском компоненте, поскольку модальный компонент должен быть функциональным компонентом для отображения только модального связанного представления. Таким образом, каждый раз, когда модальный компонент не будет отображаться и отображаться только тогда, когда видимый флаг имеет значение true.
{ this.state.visible amp;amp;
<Modal />
}
В родительском компоненте вы можете извлекать данные в componentDidMount, если сразу после первоначального рендеринга требуются данные, или componentDidUpdate, если после каждого обновления требуется выборка данных для модального. После получения данных установите состояние visible в true.
Счастливого кодирования!!!
Комментарии:
1. Я обновил вопрос, модальный должен вызывать API на основе идентификатора продукта, переданного из родительского компонента
2. Просто создайте компонент-оболочку для модального, скажем, ModalContainer, вызовите api из ModalContainer и, когда данные будут извлечены (visible: true), затем отобразите модальный компонент. Разделение проблем.
Ответ №2:
Вы можете смонтировать Modal
основанный на this.state.visible
и начать выборку, когда Modal
он смонтирован на componentDidMount или когда реквизиты меняются через 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 amp;amp; <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>
);
}
}
Ответ №3:
На самом деле в другом подходе вы можете использовать <modal/>
в другом PureComponent (например: 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>
в этом методе у вас есть только один модальный и одна область в качестве его данных, вы можете вызывать выборки и другие функции в вашем основном компоненте как другие… и если это так необходимо, вы даже можете передать функцию как свойство в модальный контейнер, чтобы :
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')
Ответ №4:
Итак, давайте предположим, что вы скрыли и показали модальный с помощью нажатия кнопки, теперь всякий раз, когда модель будет открываться внутри функции 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>
);
}
}
Ответ №5:
Вы можете использовать следующий подход:
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.props.visible amp;amp; !prevProps.visible) {
// make the API call here
}
}