I'm trying to load a modal 2 seconds after the page has been loaded. I tried setting the state on componentDidUpdate but I keep on getting active: undefined The active props determines the visibility of the modal on the page. I tried toggling it to true on browser on the react tool and my modal shows up. I'm just not sure how to load to it 2 seconds after the page loads up.
state = { show: true };
showModal = () => {
this.setState({ show: true });
};
closeModal = () => {
this.setState({ show: false });
};
render() {
const { showModal } = this.state;
return (
<React.Fragment>
....
<Modal.ModalAnimator active={showModal} onClose={this.closeModal}>
<Modal.ModalWithCross
onClose={this.closeModal}
>
<h3>Are you interested in any other Additions?</h3>
<Section>
<p>Hit “notify concierge” and we’ll be in touch shortly.</p>
</Section>
</Modal.ModalWithCross>
</Modal.ModalAnimator>
</React.Fragment>
)
}
When destructuring the state, you write showModal instead of the actual state field name show. So your first lines in the render function should read:
render() {
const { show } = this.state;
return (
<React.Fragment>
...
<Modal.ModalAnimator active={show} onClose={this.closeModal}>
...
Please try this.
state = { show: true };
closeModal = () => {
this.setState({ show: false });
};
componentDidMount() {
setTimeout(() => {
this.setState({ show: true });
}, 2000);
}
render() {
const { showModal } = this.state;
return (
let model = null;
if (this.state.show) {
let model = (
<Modal.ModalAnimator active={showModal} onClose={this.closeModal}>
<Modal.ModalWithCross
onClose={this.closeModal}
>
<h3>Are you interested in any other Additions?</h3>
<Section>
<p>Hit “notify concierge” and we’ll be in touch shortly.</p>
</Section>
</Modal.ModalWithCross>
</Modal.ModalAnimator>
)
}
<React.Fragment>
....
{model}
</React.Fragment>
)
}
Related
I have two functions which I run with a button:
this.state = {
myLimit: this.props.limit.lim,
modalOpen: false,
}
submit = () => {
// this sends state to Redux reducer
let lim = {'lim':this.state.myLimit};
this.props.updateLimit(lim);
// this sends update state for toggle in Parent component
this.props.changeToggle(false);
// function open Modal for 1,5 second like "Success"
showModal = () => {
this.setState({
modalOpen: true
});
this.timeout = setTimeout(() => {
this.setState({
modalOpen: false
})
}, 1500);
}
render(){
return (
<View style={styles.container}>
//some code
<Button onPress={ this.submit } onPressIn={ this.showModal } title='submit' />
<MyPopup visible={this.state.modalOpen}>
<View style={styles.modal}>
<Text style={styles.text}>The limit successfully changed</Text>
</View>
</MyPopup>
</View>
)
}
Parent component
//Parent component
...
this.state = {
openLimit: false,
}
toggle(toggler) {
let togglerStatus = this.state[toggler];
this.setState({
[toggler]: !togglerStatus
});
}
// run changing toggle from child 'Limit'
changeToggle = (val) => {
console.log(val)
this.setState({
openLimit: val
})
};
return(
//some code
<Child changeToggle={this.changeToggle}/>
)
It works, but not always good enough. Sometimes the submit function does not send state to Redux reducer in this this.props.updateLimit(lim) and/or not change toggle state this this.props.changeToggle(false).
So I am tried to combine it in one function:
combineFunc = () => {
// this works
// this sends state to Redux reducer
let lim = {'lim':this.state.myLimit};
this.props.updateLimit(lim)
// this part does not work
// function open Modal for 1,5 second like "Success"
this.setState({
modalOpen: true
});
this.timeout = setTimeout(() => {
this.setState({
modalOpen: false
})
}, 1500);
// this works
// this sends update state for toggle in Parent component
this.props.changeToggle(false);
}
render(){
return (
<View style={styles.container}>
//some code
<Button onPress={this.combineFunc} title='submit' />
</View>
)
}
But in this case it does not change -> this.setState({modalOpen: true}) and Modal does not open at all.
Why does it happen? Is it possible to set some order to run?
I think the problem is in setTimeout, but I need it for a popup.
Any suggestions?
Ciao the problem is in setTimeout as you said. You know this.setState is async. But it has a callback, so try this:
this.setState({
modalOpen: true
}, () => {
this.timeout = setTimeout(() => {
this.setState({
modalOpen: false
})
}, 1500);
});
I new in ReactJS and i have one few question. I defined function showModal and but console.log() and
this.setState({show:!this.state.show});.
And after that I applied
this function onClick event for div element inside map function.
1st question: When I click on div element showModal work but in console I don't see my console.log.
2nd question: I want to make when you click on one div element it must add/show few new div elements but only for one div element (on which I clicked). But now when I click on one div element it add/show new elements for all div elements which had this showModal function.
How can i fix this
import React, { Component } from "react";
import Modal from '../components/modal/form'
const DEFAULT_QUERY = 'redux';
const PATH_BASE = 'URL which work correct';
class Actions extends React.PureComponent{
constructor(){
super();
this.state = {
result:null,
show:false,
helpId:null
};
this.setSearchTopStories = this.setSearchTopStories.bind(this);
this.showModal = this.showModal.bind(this);
this.handleClickFromParent = this.handleClickFromParent.bind(this);
this.onClose = this.onClose.bind(this);
}
onClose = e => {
this.setState({ show: false});
}
handleClickFromParent = e => {
this.setState({show: !this.state.show});
}
showModal = e => {
console.log('BABE');
this.setState({show: !this.state.show})
};
setSearchTopStories(result) {
this.setState({ result });
};
componentDidMount() {
fetch(`${PATH_BASE}`)
.then(response => response.json())
.then(result => this.setSearchTopStories(result))
.catch(error => error);
};
render(){
const { searchTerm, result } = this.state;
console.log('* Actions Pure*');
console.log(result);
console.log('=');
return(
<div>
{
(result !== null) ?
result.map(
(item,index) =>
<div>
<div onClick={()=>this.showModal()}>{item.name}</div>
<Modal
id = {index}
handleClickFromParent {this.handleClickFromParent}
item = {[item]}
show = {this.state.show}
onClose = {this.onClose}>
YOLO
</Modal>
</div>
)
: null
}
</div>
)
}
}
export default Actions;
While selecting u can pass the item on method, and on click u can set the item value. Please check the below code.
Demo:
https://codesandbox.io/s/stackoverflowmodal-19i36
this.state = {
result: null,
show: false,
selectedItem:null,
helpId: null
};
//
showModal = (selectedItem) => {
this.setState({
show: !this.state.show,
selectedItem
});
};
//
class Actions extends React.PureComponent {
constructor() {
super();
this.state = {
result: null,
show: false,
selectedItem: null,
helpId: null
};
this.setSearchTopStories = this.setSearchTopStories.bind(this);
this.showModal = this.showModal.bind(this);
this.handleClickFromParent = this.handleClickFromParent.bind(this);
this.onClose = this.onClose.bind(this);
}
onClose = e => {
this.setState({
show: false
});
};
handleClickFromParent = e => {
this.setState({
show: !this.state.show
});
};
showModal = selectedItem => {
this.setState({
show: !this.state.show,
selectedItem
});
};
setSearchTopStories(result) {
this.setState({ result });
}
componentDidMount() {
fetch(`${PATH_BASE}`)
.then(response => response.json())
.then(result => this.setSearchTopStories(result))
.catch(error => error);
}
render() {
const { searchTerm, result, selectedItem } = this.state;
return (
<div>
{result && result.length
? result.map((item, index) => (
<div>
<div onClick={() => this.showModal(item)}>{item.name}</div>
</div>
))
: null}
{selectedItem && (
<Modal
id={index}
handleClickFromParent={this.handleClickFromParent}
item={[selectedItem]}
show={this.state.show}
onClose={this.onClose}
>
YOLO
</Modal>
)}
</div>
);
}
}
export default Actions;
How to set hover for itself within map in Reactjs
hoverOn = () => {
this.setState({ hover: true});
}
hoverOff = () => {
this.setState({ hover: false });
}
...
var components = posts.map((post, i) => (
.....
<span className={this.state.hover ? 'showtooltip':'hidetooltip'} onHover={this.hoverOn} onMouseOut={this.hoverOff} onClick={(e) => this.viewPost(post, e)}><i className="quickview-button"></i></span>
......
));
Since I use setState, everytime I hover on span it reflects to all list data which returned from map loop.
How can I use hover to reflect on itself element?
Thank so much
wrap this logic in a little Component:
class Foo extends React.Component {
constructor(){
this.state = { hover: false };
}
render(){
return <span
{ ...this.props }
className={ this.state.hover ? 'showtooltip':'hidetooltip' }
onHover={ () => this.setState({ hover: true }) }
onMouseOut={ () => this.setState({ hover: false }) }
/>;
}
}
and use that Component:
...
var components = posts.map((post, i) => (
.....
<Foo onClick={(e) => this.viewPost(post, e)}><i className="quickview-button"></i></Foo>
......
));
You can make hover inside state an object state = { hover: {} } and set it with index i on events i.e. this.setState({ hover: {...this.state.hover, i: true }});.
Then pass i parameter into those methodsonHover={(i) => this.hoverOn(i)}
And change className setup to <span className={this.state.hover[i] ? 'showtooltip':'hidetooltip'} (thanks to #kenny for noticing this)
The expected
I want to put a loading state in the content of tab, whenever user clicked on the tab title to switch tab, a flag is passed down through children.
The problem
I have this App component, I fake its api call using a setTimeout
class App extends Component {
state = {
loading: false,
data: []
}
getData = () => {
return new Promise(resolve => {
return setTimeout(() => {
resolve(
[
{
id: 1,
name: "Kelas A",
list: ["Jane", "Ali", "Ahmad"]
},
{
id: 2,
name: "Kelas B",
list: ["May", "Henry", "Ben"]
}
]
)
},500)
})
}
async componentDidMount() {
this.setState({
loading: true
})
const data = await this.getData()
this.setState({
data,
loading: false
})
}
//loadingComponent = () => <div>Loading...</div>;
render() {
const { data, loading } = this.state
return (
<Tabs
activeTab={1}
loading={loading}
//loadingComponent={this.loadingComponent()}
>
{data.map(o => (
<Tab
id={o.id}
>
<Tab.Title>{o.name}</Tab.Title>
<Tab.Content>
{o.list.join(", ")}
</Tab.Content>
</Tab>
))}
</Tabs>
);
}
}
I pass loading state as prop to Tabs children component, it worked, I can see true and false:
class Tabs extends Component {
static defaultProps = {
activeTab: 1
};
static getDerivedStateFromProps(nextProps, prevState) {
if(nextProps.loading !== prevState.loading){
return {
loading: nextProps.loading
}
}
}
state = {
activeTab: this.props.activeTab
};
changeTab = tab => {
this.setState({ activeTab: tab });
};
render() {
const { children } = this.props;
const { activeTab, loading } = this.state;
console.log('true or false before pass to children', loading)
return (
<div className="tabs">
{React.Children.map(children, child =>
React.cloneElement(child, {
loading,
activeTab,
changeTab: this.changeTab
})
)}
</div>
);
}
}
But I pass that loading as prop to Tabs's children which is Tab, the loading flag became just false? I can't spot the problem.
class Tab extends Component {
static Title = ({ children, tabId, activeTab, handleTabClick }) => {
return (
<div
className={`title ${tabId === activeTab ? "active" : ""}`}
onClick={handleTabClick}
>
{children}
</div>
);
};
static Content = ({ children, tabId, activeTab, loading }) => {
loading && 'Loading...' //won't work coz loading is always false, I wonder why
return tabId === activeTab ? (
<div className="content">{children}</div>
) : null;
};
render() {
return React.Children.map(this.props.children, child =>
React.cloneElement(child, {
handleTabClick: () => this.props.changeTab(this.props.id),
tabId: this.props.id,
activeTab: this.props.activeTab,
loading: this.props.loading // why always false?
})
);
}
}
My demo
https://codesandbox.io/s/o41r35n2qz
this.props.loading is always false in your child component because it does not even get rendered when it's true, as data is empty when loading is true so data.map does not create any components.
You would need to move the loading check to a parent component that is rendered even when data is empty. Eg. https://codesandbox.io/s/xpy3r3575z
EDIT:
If you want to fetch the data separately for each tab, then you need to create separate API calls, one for fetching tab titles to render the tab headers, and one for fetching the data for the active tab.
Initially when you set it as false
state = {
loading: false,
data: []
}
When the component has been loaded you simulate it to true and then false
async componentDidMount() {
this.setState({
loading: true
})
const data = await this.getData()
this.setState({
data,
loading: false
})
}
But you never received component state changes in child components.
You can get changes of a state using componentWillReceiveProps()
So you can give it a try as
class Tab extends Component {
componentWillReceiveProps(props) { //here you will get changes whenever state changes
let loading = props.loading
this.setState({loading});
}
render() {
return React.Children.map(this.props.children, child =>
React.cloneElement(child, {
handleTabClick: () => this.props.changeTab(this.props.id),
tabId: this.props.id,
activeTab: this.props.activeTab,
loading: this.state.loading //through state
})
);
}
}
could you please tell me how to hide the component in reactJS and show another component?I have one button and text (hello).on button click, I want to hide button as well as text and show another text bye
here is my code
https://codesandbox.io/s/50lj63xvk
showBankDetail = () => {
console.log("====");
this.setState({
validForm: true
});
};
render() {
const validForm = !this.state.validForm;
return { validForm } ? (
<div>
heloo<button onClick={this.showBankDetail}>hide</button>
</div>
) : (
<div>bye</div>
);
}
One way is to put it on a separate variable first
showBankDetail = () => {
console.log("====");
this.setState({
validForm: true
});
};
render() {
const validForm = !this.state.validForm;
let form;
if (validForm) {
form = (<div>
heloo<button onClick={this.showBankDetail}>hide</button>
</div>);
} else {
form = (<div>bye</div>);
}
return ({form});
}
{ validForm } is creating an object with property validForm and value of validForm (e.g. true or false). You can read more about it here. Your code should look like this
showBankDetail = () => {
console.log("====");
this.setState({
validForm: true
});
};
render() {
const validForm = !this.state.validForm;
return validForm ? (
<div>
heloo<button onClick={this.showBankDetail}>hide</button>
</div>
) : (
<div>bye</div>
);
}
There are a few things you should look at. First off you want to toggle the validForm state, so do that in the showBankDetail function. You could return different elements based on validForm, but you can also do it inline. See:
class App extends React.Component {
constructor() {
super();
this.state = {
validForm: false
};
}
showBankDetail = () => {
this.setState({
validForm: !this.state.validForm
});
};
render() {
return (
<div>
{ this.state.validForm ?
<div>heloo</div> :
<div>bye</div>
}
<button onClick={this.showBankDetail}>hide</button>
</div>
)
}
}