Rendering a component in order/after one has rendered (React) - reactjs

I have an app that displays data from an API and a button for loading more.
The problem I have is that the button flashes on the screen before the data list is fetched and displayed.
I want the button to display only at the bottom of the page after the list.
What is a way I can do this?
The code :
useEffect(() => {
setLoading(true);
fetchTopRatedMovies(pageNumber).then((newData) =>
setApiData({
...newData,
results: [...apiData.results, ...newData.results]
})
);
setLoading(false);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pageNumber]);
return (
<div className='top-rated-page-wrapper'>
{isLoading ? (
<Loader />
) : (
<>
<MovieList results={results} />
<PageButton pageLimit={pageLimit} loadMore={loadMore} />
</>
)}
</div>
To clarify.
The button loads first and flashes before the data is rendered.
The button is then in the position where I want it at the bottom of the page.
I don't want to button to be visible until the data has been rendered.

You could use conditional render to render load more button when data > 0
{ apiData ? <PageButton pageLimit={pageLimit} loadMore={loadMore} /> : null }

I believe this article will answer your question. The author uses the same hook and speaks specifically how to manage the lifecycle event with a state variable.
https://daveceddia.com/useeffect-hook-examples/

Related

React toggling between clickable words that pull up <Elements/>

Somewhat new to React.
I want to be able to toggle between React elements CreateUser, EditUser, and ListUser.
It would be great to have a clickable text that when selected pulls up that element and its
corresponding stuff. In the case of Create its a field with a save button.
What is the best way to have my CrudSelector class list all three texts, make them clickable and pull up the stuff inside toggling to the selected one at a time?
Welcome. Always a good idea to share code with your question.
You'll want to use some kind of state which tells your parent component which child component to show. Kind of like this in your React functional component:
const [ featureToShow, setFeatureToShow ] = useState('list')
return (
<>
{/* Show some buttons to change the state */}
<button onClick={() => setFeatureToShow('list')}>Show User List</button>
<button onClick={() => setFeatureToShow('create')}>Create User</button>
<button onClick={() => setFeatureToShow('edit')}>Edit User</button>
{/* Depending on what is in the state show that component */}
{ featureToShow === 'list' ? <ListUser /> : null }
{ featureToShow === 'create' ? <CreateUser /> : null }
{ featureToShow === 'edit' ? <EditUser /> : null }
</>
)
In reality you'll probably want to enable clicking on the user's name in ListUser to show the EditUser component.

Loading screen using Semantic UI React

I'm trying to display a loading screen while the rest of the App complete loading using Semantic UI React.
The problem is that when i load the page it shows only the text "Loading" and it renders the Loader properly only after a few seconds like if it didn't have any css. The purpose of having a loader is that it has to be in front of the page while other content renders but if it has the same problem I don't know how to show content only when it rendered and ready to be displayed.
I'm using this code from the semantic ui react webpage (https://react.semantic-ui.com/elements/loader/#types-loader)
function App() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 2000)
}, [])
return (
<div>
<div style={{ display: loading ? "block" : "none" }}>
<Dimmer active>
<Loader content='Loading' />
</Dimmer>
</div>
<div style={{ display: loading ? "none" : "block" }}>
// Content that needs time to render
</div>
</div>
)
}
export default App;
What can I do in order to display content only when it's done rendering?
Try putting it in a Segment. Furthermore I wouldn't use the technique you use to display or hide things, what I always do is:
{condition && <Component />}
So in this case your code would be:
{loading === true && <Segment><Dimmer active><Loader content='Loading' /></Dimmer></Segment>}
and
{loading === false && <>
{/* Content that needs time to render */}
</>}
And then of course set loading to false whenever your API calls are finished.
I hope this helps you and answers the question, if not please point it out :).

How to display detail page from search results in ResultCard?

Preconditions: React application using appbaseio/reactivesearch
Problem: I am trying to open a simple detail page in the same window (e.g. as a popup window triggered via onclick handler) when I click on a search result. Search results are being displayed by the ResultCard component. Anybody had a similar issue and solved it?
I see there is the url parameter (here: "profile") in the ResultCard component, but it just redirects to the specified url in another tab window.
import {ReactiveBase, DataSearch, ResultCard} from
appbaseio/reactivesearch";
// ...some more code
<div className="container">
// connector to appbase.io
<ReactiveBase
app="myapp"
credentials="xxx"
theme={{
primaryColor: "#ffe067"
}}
>
// search bar
<DataSearch
componentId="SearchSensor"
dataField={["gebot_name", "info"]}
className="search"
/>
// display search results in a list with title and description
<ResultCard
className="right-col"
componentId="SearchResult"
size={10}
onData={data => ({
title: data.gebot_name,
description: data.description,
url: "profile"
})}
react={{
and: ["SearchSensor"]
}}
/>
</ReactiveBase>
</div>
So to what I understand from your question you want to display a Modal when clicking on result item and show all the details.
If this is the case you can use ReactiveList and render the data according to your choice. For eg:
In v2:
<ReactiveList
...
onData={ res => (
<div onClick={() => this.handleModal(res)} >{Content}</div>
)
}
/>
With this.handleModal you can handle the Modal and display the data.
In v3
<ReactiveList
...
renderItem={ res => (
<div onClick={() => this.handleModal(res)} >{Content}</div>
)
}
/>
Check documentation here:
For v3: https://opensource.appbase.io/reactive-manual/result-components/reactivelist.html
For v2: https://opensource.appbase.io/reactive-manual/v2/result-components/reactivelist.html

React - Setting state to target with onClick method

I am trying to recreate a tabs component in React that someone gave me and I am getting stuck while getting the onClick method to identify the target.
These are the snippets of my code that I believe are relevant to the problem.
If I hardcode setState within the method, it sets it appropriately, so the onClick method is running, I am just unsure of how to set the tab I am clicking to be the thing I set the state to.
On my App page:
changeSelected = (event) => {
// event.preventDefault();
this.setState({
selected: event.target.value
})
console.log(event.target.value)
};
<Tabs tabs={this.state.tabs} selectedTab={this.state.selected}
selectTabHandler={() => this.changeSelected}/>
On my Tabs page:
{props.tabs.map(tab => {
return <Tab selectTabHandler={() => props.selectTabHandler()} selectedTab={props.selectedTab} tab={tab} />
})}
On my Tab page:
return (
<div
className={'tab active-tab'}
onClick={props.selectTabHandler(props.tab)}
>
{props.tab}
</div>
When I console.log(props.tab) or console.log(event.target.value) I am receiving "undefined"
There are a few issues causing this to happen. The first issue is that you wouldn't use event.target.value in the Content component because you aren't reacting to DOM click event directly from an onClick handler as you are in Tab, instead you are handling an event from child component. Also keep in mind that event.target.value would only be applicable to input or similar HTML elements that have a value property. An element such as <div> or a <span> would not have a value property.
The next issues are that you aren't passing the tab value from Tabs to Content and then from within Content to it's changeSelected() handler for selectTabHandler events.
In addition the onClick syntax in Tab, onClick={props.selectTabHandler(props.tab)} is not valid, you will not be able to execute the handler coming from props and pass the props.tab value. You could instead try something like onClick={() => props.selectTabHandler(props.tab)}.
Content - need to pass tab value coming from child to changeSelected():
render() {
return (
<div className="content-container">
<Tabs
tabs={this.state.tabs}
selectedTab={this.state.selected}
selectTabHandler={tab => this.changeSelected(tab)}
/>
<Cards cards={this.filterCards()} />
</div>
);
}
Tabs - need to pass tab coming from child to selectTabHandler():
const Tabs = props => {
return (
<div className="tabs">
<div className="topics">
<span className="title">TRENDING TOPICS:</span>
{props.tabs.map(tab => {
return (
<Tab
selectTabHandler={tab => props.selectTabHandler(tab)}
selectedTab={props.selectedTab}
tab={tab}
/>
);
})}
</div>
</div>
);
};
export default Tabs;
Also don't forget the unique key property when rendering an array/list of items:
<Tab
key={tab}
selectTabHandler={tab => props.selectTabHandler(tab)}
selectedTab={props.selectedTab}
tab={tab}
/>
Here is a forked CodeSandbox demonstrating the functionality.

React - Change Button HTML to loader on click

I have an Alerts component which is responsible for rendering alerts from JSON supplied to it's props:
alert.js (cut down for brevity)
createAlert(alerts) {
return alerts.map(content => (
<Col key={content.ID} s={12}>
<div className="chip">
<Icon className="alert">error_outline</Icon>
<p>{content.Comment}</p>
<span onClick={() => this.props.onRead(content.ID)}>
<Icon className="closeAlert">close</Icon>
</span>
</div>
</Col>
));
}
render() {
let content = {};
if (!this.props.content) {
//Alerts are null so they are still loading.. show loader
content = this.createLoader();
} else if (!this.props.content.success){
//Error getting alerts
content = this.createAlertError(this.props.content.error);
}
else if (this.props.content.alerts.length === 0) {
//Alert array is null, therefor no alerts
content = this.createNoAlerts();
} else {
//Render Alerts
content = this.createAlert(this.props.content.alerts);
}
return <div>{content}</div>;
}
}
In the above snippit, you can see that if
this.props.alerts
is an array with elements, then it will run
createAlert()
which will create an array of React Components (in this case its just React-Materialize component which is just a <div></div>)
the part I am interested in is the span with the onClick event
<span onClick={() => this.props.onRead(content.ID)}>
<Icon className="closeAlert">close</Icon>
</span>
This run an event from the parent component.
The method that is run in the parent is as follows:
alertRead(id) {
this.props.deleteAlert(id);
}
What I would like, is some way to add a spinning loader icon into the button on the click, in jQuery it would be:
$(button).on("click", function(){
this.html("<i class='fa fa-spin fa-spinner'></i>"); //Spinner Icon
});
The question is, how do I edit the HTML of the button that is clicked on click?
No Redux version
I don't see any redux relation in the code so I will assume that you are not using it or not using it in this particular flow.
What you need to do is to add state to the Alert component and do two things in onClick handler:
() => { this.props.onRead(content.ID); this.setState({clicked: true});}
Of course you need to have state initialization with clicked: false. Second thing is to use this state in rendering:
{this.state.clicked && <Loader />}
{!this.state.clicked && <YourButton />}
So when clicked show loader when not clicked show button. Above code examples are only for showing you the right path.
Version assuming of Redux using.
If you are using redux then alert needs to have connection with the store like:
connect((state) => ({ isClicked: getIsButtonClicked(state)}), { dispatchClick })(AlertComponent)
And you need to dispatch click action after click ( it will set the store state responsible for that - clicked on true.
() => { this.props.onRead(content.ID); this.props.dispatchClick();}
Also finnaly you need to use this prop in rendering:
{this.props.isClicked && <Loader />}
{!this.props.isClicked && <YourButton />}
This solution will cover all instances of Alert component. I am not covering here the redux part.

Resources