React component ignore displaying text for empty obj - javascript

I have a react component with a method that reads some data from an object and then returns the text on its status on another component.
The problem is that when the application is loading at first the obj length will be 0 initially and when the object data is loaded it will then
update and the obj.length will be higher than 0.
The what happens is this:
Scenario 1 (obj will actually have data)
-- App Loading
-- getTxt checks if obj is empty
-- As data is not loaded yet on the first call obj.length will return 0 so 'No Data Found' is displayed
-- Then when the app finishes loading it then updates and the obj.length > 0 so 'Found the data' is displayed
or
Scenario 2 (obj will be empty)
-- App Loading
-- getTxt checks if obj is empty
-- As data is not loaded yet on the first call obj.length will return 0 so 'No Data Found' is displayed
-- Then when the app finishes loading it then updates and the obj is actually empty so it can stay the same.
My problem is that if after the app is loaded and obj.length re-checked it returns > then 0 then I don't want to display the first 'No Data Found',
but I need to have the condition just in case after the app has finished loading the data the data is still = 0
Here is the code:
import React from 'react'
class MyComponent extends React.Component {
getTxt() {
if (this.props.obj.length > 0) {
return 'Found the data';
} else if (this.props.obj.length == 0) {
return 'No Data Found';
}
return 'Searching Data'
}
render() {
return <SomeComponent text={this.getTxt()}/>
}
}
export {MyComponent}
What can I do in order to get this done?

As stated in the comments by Felix Kling.
You have three different states.
Initial state
No data
There is some data
Initial state will have the data props set to null. After the data was received it could be an empty object {} or an object with some information.
I would probably write this in the following way:
class MyComponent extends React.Component {
getStatus() {
const { data } = this.props;
if (data === null) {
return "Searching data"
}
if (Object.keys(data).length === 0) {
return "No data was found"
}
return "Found some data"
}
render() {
return <SomeComponent text={this.getStaus()}/>
}
}
This is almost perfect because I would like to separate logic from the view. I will have a reducer that will get the data and upon its values/length it will determine the status.
const statusReducer = (data) => {
if (data === null) {
return "Searching data"
}
if (Object.keys(data).length === 0) {
return "No data was found"
}
return "Found some data"
}
class MyComponent extends React.Component {
state = { data: null }
componentDidMount() {
getData()
.then(resp => resp.json)
.then(resp => this.setState({data: resp.data})
}
render() {
return <SomeComponent text={statusReducer(this.state.data)} />
}
}
You may ask what's the point of passing this to another function (reducer)? First, as I mentioned, separating the logic from the view. Second, statusReducer can be reused in other components. Third, easier to test the code.
NOTE: We only took care of the happy path. However, if there was a problem with the request or the response contains error, we probably get the wrong status.
To handle such case lets look at a different approach. Lets have data and status in state
class MyComponent extends React.Component {
state = { data: null, status: 'PENDING' }
componentDidMount() {
getData()
.then(resp => resp.json)
.then(resp => this.setState({data: resp.data, status: 'COMPLETE'})
.catch(err => this.setState(data: err.Message, status: 'ERROR'})
}
render() {
switch(this.state.status) {
case 'COMPLETE':
return <SomeComponent text={statusReducer(this.state.data)} />
case 'ERROR':
return <ErrorComponent message={this.state.data} />
case 'PENDING':
return <Spinner />
default:
// there is a runtime/compiling error.
// Notify it in you console.log or something
return null // Here I am silently failing but that's not a good practice
}
}
}
We could do even better if we move the switch-case statement to another function and call it loadReducer. But I will let you decide whether to do it or not.
Please notice Eitan's solution too. He uses both componentDidMount and componentWillUpdate to update status.

It sounds like you don't want to render anything until the data is received?
What I do when I need to do this is use component state to keep track of loading status. When the component mounts, set state.loading to true.
componentDidMount() {
this.setState({loading: true})
}
Set loading to false once everything is updated.
componentDidUpdate() {
if (this.state.loading) {
this.setState({loading: false})
}
}
And in the render function, conditionally render based on loading state.
render() {
const text = this.state.loading ? "Loading..." : this.getTxt()
return <SomeComponent text={text}/>
}

I agree with Felix in the comments. You may be better off with a nested ternary in a functional component. The component should update whenever props to it obj are updated.
export const myComponent = (props) => {
return (
<SomeComponent
text={ props.obj ?
props.obj.length > 0 ?
'Found Data'
:
'No Data Found'
:
'Searching'
}
/>
)
}

Related

How to re-rendering react class component when state is changed

New to both react and javascript and was wondering how do we re-render the component?
I need to make sure that the details (E.g. badge counter) in button component re-render everytime we get a change in facets.
I see some older attempts by other developers to set state but it doesn't seem to be working so i need some guidance on the following.
How to detect when there is a change in facets?
How do we re-render the component everytime we get a change in facets?
class SearchResult extends React.Component {
constructor(props) {
super(props);
this.state = {
_query: props.query,
_facets: props.facets,
_hasLoaded: false,
};
}
render() {
const {
onEntityClick, facets, entity, total, pagingTotal, isFilterSubmitted, loading, query,
} = this.props;
const {
_query, _facets, _hasLoaded,
} = this.state;
if ((_query !== query && query !== '*') && !loading) {
this.setState({
_query: query,
_facets: facets,
});
}
if ((_query === query && query === '*' && !_hasLoaded) && !loading) {
this.setState({
_query: query,
_facets: facets,
_hasLoaded: true,
});
}
return (
<Fragment>
<ButtonComponent
btnTheme="gray"
size="small"
label="Note"
icon="note"
// eslint-disable-next-line no-nested-ternary
badgeCounter={!loading ? entity === 'note' && isFilterSubmitted ? pagingTotal : _facets.note : 0}
disabled={entity === 'note'}
callbackFunc={() => onEntityClick('note')}
/>
</Fragment>
);
}
}
You're making an antipattern in your code:
this.setState() should never be called inside the render() function.
Instead, what you would like to do is check componentDidUpdate():
componentDidUpdate(prevProps) {
if (prevProps.query !== props.query && query !== "*") {
...
}
}
This guarantees a re-rendered so you don't need to worry about "manually" re-rendering.
Also note that props.query as well as other values, don't need to be saved in the component state unless you need a modified copy of it -- that's what didUpdate will do.
You can try componentWillReceiveProps LC method, if there is a change in props and set the state(re-render) of the component acc. to that change.
UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
console.log(nextProps.facets);
console.log(this.state._facets);
if (nextProps.facets !== this.state._facets) {
this.setState({
_facets: 'YES'
})
}
}

How to update state of component in componentDidUpdate() without being stuck in an infinite re render?

I have a component with a componentDidMount() method that calls a method called getData() which gets the initial data and sets the initial state of the component.
class LogsSettings extends React.Component {
constructor(props) {
super(props);
this.settingsUrls = [
"/ui/settings/logging"
];
this.state = {
configSettings: {},
formSchema: formSchema
};
this.configSettings = {};
this.selected = "general";
}
getData = (url, selectedSetting) => {
fetch(url)
.then((response) => {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
response.json().then((response) => {
//pass formschema here
console.log(selectedSetting);
let newFormSchema = this.setNonDefaultValues(response.data, formSchema.subsections);
Object.assign(this.configSettings, response.data);
this.setState({
configSettings : this.configSettings,
formSchema: newFormSchema
});
});
}
)
.catch((err) => {
console.log('Fetch Error :-S', err);
});
};
componentDidMount() {
this.settingsUrls.map((settingUrl) => {
this.getData(settingUrl, this.selected)
})
}
componentDidUpdate() {
this.settingsUrls.map((settingUrl) => {
this.getData(settingUrl, this.props.selectedSetting)
})
}
render() {
return (
<div className="card-wrapper">
<h2>{formSchema.label.toUpperCase()}</h2>
{
formSchema.subsections.map((subSection) => {
return (
<>
<h3>{subSection['description']}</h3>
<div style={{marginBottom: '10px'}}></div>
{
subSection['input_fields'].map((inputField) => {
return buildForm(inputField, this.handleChange)
})
}
<hr></hr>
</>
)
})
}
<button className="button button-primary">Save Changes</button>
</div>
)
}
}
The selectedSetting parameter that gets passed to the getData() method in this component will change however and when this changes, I need to change the state of the component and get new data specific to the changed selectedSetting parameter.
The new selectedSetting is passed into the component as a prop. The problem is that I can't pass the new selectedSetting parameter to my getData method to update the state of the component as it gets caught in an infinite loop.
How do I go about passing the new selectedSetting to the getData() method without getting caught in an infinite loop? Is this even possible? If not, what is the best approach I should take?
note the selectedSetting parameter isn't used in the getData() function yet but will be and it will be used to get data from an API call and a new form schema which will then lead to the ConfigSettings and formSchema states being changed
If you look closely on the lifecycle of your component, after mount, you'll fetch then update the component. This will trigger the componentDidUpdate lifecycle method which will do the same thing, causing the infinite loop. You need to have a flag that checks whether this.props.selected changed. If it didn't, don't fetch the data else fetch as normal. In the update method, you have access to the previous props. (You may also do this in componentShouldUpdate method, but it'll be just outright risky)
componentDidUpdate(prevProps) {
if( prevProps.selectedSetting !== this.props.selectedSetting ){
this.settingsUrls.map((settingUrl) => {
this.getData(settingUrl, this.props.selectedSetting)
})
}
}
also just a heads up, I noticed that your didMount method, uses a default of "general" as the selected setting, since you want to be using this.props.selectedSetting might be better if it was the one being used instead and just set default props to "general".

getDerivedStateFromProps, change of state under the influence of changing props

I click Item -> I get data from url:https: // app / api / v1 / asset / $ {id}. The data is saved in loadItemId. I am moving loadItemId from the component Items to the component Details, then to the component AnotherItem.
Each time I click Item the props loadItemId changes in the getDerivedStateFromProps method. Problem: I'll click Element D -> I see in console.log 'true', then I'll click Element E --> It display in console.log true andfalse simultaneously, and it should display only false.
Trying to create a ternary operator {this.state.itemX ['completed'] ? this.start () : ''}. If {this.state.itemX ['completed'] call the function this.start ()
Code here: stackblitz
Picture: https://imgur.com/a/OBxMKCd
Items
class Items extends Component {
constructor (props) {
super(props);
this.state = {
itemId: null,
loadItemId: ''
}
}
selectItem = (id) => {
this.setState({
itemId: id
})
this.load(id);
}
load = (id) => {
axios.get
axios({
url: `https://app/api/v1/asset/${id}`,
method: "GET",
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => {
this.setState({
loadItemId: response.data
});
})
.catch(error => {
console.log(error);
})
}
render () {
return (
<div >
<Item
key={item.id}
item={item}
selectItem={this.selectItem}
>
<Details
loadItemId={this.state.loadTime}
/>
</div>
)
}
Item
class Item extends Component {
render () {
return (
<div onClick={() => this.props.selectItem(item.id}>
</div>
)
}
}
Details
class Details extends Component {
constructor() {
super();
}
render () {
return (
<div>
<AnotherItem
loadItemId = {this.props.loadItemId}
/>
</div>
)
}
}
AnotherItem
class AnotherItem extends Component {
constructor() {
super();
this.state = {
itemX: ''
};
}
static getDerivedStateFromProps(nextProps, prevState) {
if(nextProps.loadItemId !== prevState.loadItemId) {
return { itemX: nextProps.loadItemId }
}
render () {
console.log(this.state.itemX ? this.state.itemX['completed'] : '');
{/*if this.state.loadX['completed'] === true, call function this.start()*/ }
return (
<button /*{this.state.loadX['completed'] ? this.start() : ''}*/ onClick={this.start}>
Start
</button>
);
}
}
here:
selectItem = (id) => {
this.setState({
itemId: id
})
this.load(id);
}
you call setState(), then 'Item' and 'Details' and 'AnotherItem' call their render method. so you see log for previous 'loadItemId'.
when 'load' method work done. here:
this.setState({
loadItemId: response.data
});
you setState() again, then 'Item' and 'Details' and 'AnotherItem' call their render method again. in this time you see log for new 'loadItemId'.
solution
setState both state in one place. after load method done, instead of:
this.setState({
loadItemId: response.data
});
write:
this.setState({
itemId: id,
loadItemId: response.data
});
and remove:
this.setState({
itemId: id
})
from 'selectItem' method.
Need some clarification, but think I can still address this at high level. As suggested in comment above, with the information presented, it does not seem that your component AnotherItem actually needs to maintain state to determine the correct time at which to invoke start() method (although it may need to be stateful for other reasons, as noted below).
It appears the functionality you are trying to achieve (invoke start method at particular time) can be completed solely with a comparison of old/new props by the componentDidUpdate lifecycle method. As provided by the React docs, getDerivedStateFromProps is actually reserved for a few 'rare' cases, none of which I believe are present here. Rather, it seems that you want to call a certain method, perhaps perform some calculation, when new props are received and meet a certain condition (e.g., not equal to old props). That can be achieved by hooking into componentDidUpdate.
class AnotherItem extends Component {
constructor(props) {
super(props);
this.state = {}
}
start = () => { do something, perform a calculation }
// Invoked when new props are passed
componentDidUpdate(prevProps) {
// Test condition to determine whether to call start() method based on new props,
// (can add other conditionals limit number of calls to start, e.g.,
// compare other properties of loadItemId from prevProps and this.props) .
if (this.props.loadItemId && this.props.loadItemId.completed === true) {
//Possibly store result from start() in state if needed
const result = this.start();
}
}
}
render () {
// Render UI, maybe based on updated state/result of start method if
// needed
);
}
}
You are encountering this behaviour because you are changing state of Items component on each click with
this.setState({
itemId: id
})
When changing its state, Items component rerenders causing AnotherItem to rerender (because that is child component) with it's previous state which has completed as true (since you've clicked element D before). Then async request completes and another rerender is caused with
this.setState({
loadItemId: response.data
});
which initiates another AnotherItem rerender and expected result which is false.
Try removing state change in selectItem and you'll get desired result.
I'd suggest you read this article and try to structure your code differently.
EDIT
You can easily fix this with adding loader to your component:
selectItem = (id) => {
this.setState({
itemId: id,
loading: true
})
this.load(id);
}
load = (id) => {
axios.get
axios({
url: `https://jsonplaceholder.typicode.com/todos/${id}`,
method: "GET"
})
.then(response => {
this.setState({
loading: false,
loadItemId: response.data
});
})
.catch(error => {
console.log(error);
})
}
render() {
return (
<div >
<ul>
{this.state.items.map((item, index) =>
<Item
key={item.id}
item={item}
selectItem={this.selectItem}
/>
)
}
</ul>
{this.state.loading ? <span>Loading...</span> : <Details
itemId={this.state.itemId}
loadItemId={this.state.loadItemId}
/>}
</div>
)
}
This way, you'll rerender your Details component only when you have data fetched and no unnecessary rerenders will occur.

React: Calling setState within render method throws error

As the title suggests, only after the first message received in my chat-window - this initial message is retrieved from a GET request so it's not synchronous - I want to show/render a button. At the moment it throws an error saying I cant set the state within the render method.
I also tried the show logic in the button class as well as the 'parent' class which is my messagelist which I'm putting the button in its render method.
There is this.props.messages which is an array of the messages and so is 'messages'. this.props.messages[0].data.text is the first message, although it does console many times each messsage in the dev tools when i try console it, and of course it throws the setState error when i try to show the button.
I have a simple button class:
class Button extends Component {
render() {
return (
<div>
{<button>Return</button >}
</div>
)
}
}
export default Button;
and my messageList class, where I have the this.props.messages which is an array of the messages, this.props.messages[0] is the first message , and message..which console's every single message if i console.log it.
If i write either (if message.data.text OR this.props.messages[0] === 'my first string') { console.log ('..... '}then it always counts as true and consoles and the setstate goes into a loop.
import Message from './Messages'
import Button from './Button'
class MessageList extends Component {
constructor(props) {
super(props);
this.state = {
showing: false,
};
this.showButton = this.showButton.bind(this);
}
showButton() {
const { showing } = this.state;
this.setState({
// toggle value of `showing`
showing: !showing,
});
}
componentDidUpdate(prevProps, prevState) {
this.scrollList.scrollTop = this.scrollList.scrollHeight;
}
onlyInitialMessage(message) {
if (this.props.messages[0].data.text = `Hi I'm Joe your store assistant, I'm here to help. Here's what I can do: Answer questions on store policies, process a return or just general inquiries.`) {
this.showButton();
}
}
// way to render a function.
// {this.renderIcon()}
render() {
return (
<div className="sc-message-list" ref={el => this.scrollList = el}>
{this.props.messages.map((message, i) => {
{ this.onlyInitialMessage() }
return <Message message={message} key={i} />
})}
{this.state.showing && <Button />}
</div>)
}
}
I'm not sure If I have my logic in the wrong place here? I tried to move it around lots of times, I am new to React!
Firstly, The issue is that you are setting state in the render method indirectly by calling { this.onlyInitialMessage() } in render.
Secondly, your if condition is not comparing value but assinging value which will always return true
if (this.props.messages[0].data.text === `Hi I'm Joe your store assistant, I'm here to help. Here's what I can do: Answer questions on store policies, process a return or just general inquiries.`) {
To solve it, you must call onlyInitialMessage within componentDidMount
import Message from './Messages'
import Button from './Button'
class MessageList extends Component {
constructor(props) {
super(props);
this.state = {
showing: false,
};
this.showButton = this.showButton.bind(this);
}
componentDidMount() {
this.onlyInitialMessage();
}
showButton() {
const { showing } = this.state;
this.setState({
// toggle value of `showing`
showing: !showing,
});
}
componentDidUpdate(prevProps, prevState) {
this.scrollList.scrollTop = this.scrollList.scrollHeight;
}
onlyInitialMessage(message) {
if (this.props.messages[0].data.text == `Hi I'm Joe your store assistant, I'm here to help. Here's what I can do: Answer questions on store policies, process a return or just general inquiries.`) {
this.showButton();
}
}
// way to render a function.
// {this.renderIcon()}
render() {
return (
<div className="sc-message-list" ref={el => this.scrollList = el}>
{this.props.messages.map((message, i) => {
return <Message message={message} key={i} />
})}
{this.state.showing && <Button />}
</div>)
}
}

React redux async mapStateToProps

How come when calling mapDispatchToProps functions in componentDidMount,
mapStateToProps totalDoctorCount: state.doctors.totalDoctorCount wont always load on time and I would get undefined result in console.log("this.props.totalDoctorCount: "+this.props.totalDoctorCount );.
I know it's the nature of async, but is there a way to fix it am i doing something wrong here.
Full Code :
doctorActions
export function getDoctors(filterType){
return function(dispatch){
axios.get("/api/doctors/"+filterType)
.then(function(response){
dispatch({type:"GET_DOCTORS",payload:response.data});
})
.catch(function(err){
dispatch({type:"GET_DOCTORS_REJECTED",payload:err});
})
}
}
export function getTotalDoctors(){
return function(dispatch){
axios.get("/api/getTotalDoctors/")
.then(function(response){
dispatch({type:"TOTAL_DOCTORS",payload:response.data});
console.log(response.data);
})
.catch(function(err){
//console.log(err);
dispatch({type:"TOTAL_DOCTORS_REJECTED",payload:"there was an error rortal doctors"});
})
}
}
doctorReducer
export function doctorsReducers(state={
doctors:[],
}, action){
switch(action.type){
case "GET_DOCTORS":
// return the state and copy of boos array from state
return {...state,doctors:[...action.payload]}
break;
case "TOTAL_DOCTORS":
// return the state and copy of boos array from state
return {
...state,
totalDoctorCount:action.payload
}
break;
}
return state;
}
server API
app.get('/doctors/:filterType',function(req,res){
let filterType = req.params.filterType;
var query = {};
if(filterType == "dateCreated"){
query = {date_created: 'desc'};
}else if(filterType == "dateUpdated"){
query = {date_updated: 'desc'};
}
Doctors.find({}).sort(query).limit(3).exec(function(err,doctors){
if(err){
throw err;
}
res.json(doctors);
});
});
app.get('/getTotalDoctors',function(req,res){
Doctors.count({}, function(err, count){
if(err){
throw err;
}
res.json(count);
});
});
component
class MainAdmin extends React.Component{
constructor(){
super();
this.state = {
selected_filter:"dateCreated"
};
}
openAddDoctorModal = () => {
this.setState({AddDoctorModal:true});
}
closeAddDoctorModal = () => {
this.setState({AddDoctorModal:false});
}
componentDidMount(){
this.props.getTotalDoctors();
this.props.getDoctors(this.state.selected_filter);
}
loadPage = (pageNum) => {
//alert(pageNum);
this.props.loadPage(pageNum,this.state.selected_filter);
}
render(){
const doctorsList = this.props.doctors.map(function(doctorsArr){
return(
<Col xs={12} sm={12} md={12} key={doctorsArr._id}>
<DoctorsItem
_id = {doctorsArr._id}
doc_fname = {doctorsArr.doc_fname}
doc_lname = {doctorsArr.doc_lname}
/>
</Col>
)
});
//const lengthPage = parseInt(this.props.totalDoctorCount/3);
console.log("this.props.totalDoctorCount2: "+this.props.totalDoctorCount );
const pages = parseInt(this.props.totalDoctorCount/3, 10);
console.log("pages: "+pages );
const pageNums = [...Array(pages)].map((pageNum, i) => {
return(
<Col xs={2} sm={2} md={2} key={i+1}>
<Button onClick={() => this.loadPage(i+1)} bsStyle="success" bsSize="small">
{i+1}
</Button>
</Col>
)
});
return(
<Well>
<Row style={{marginTop:'15px'}}>
{doctorsList}
</Row>
<Row style={{marginTop:'15px'}}>
{pageNums}
</Row>
</Well>
)
}
}
function mapStateToProps(state){
return{
doctors: state.doctors.doctors,
totalDoctorCount:state.doctors.totalDoctorCount
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({
getDoctors:getDoctors,
loadPage:loadPage,
getTotalDoctors:getTotalDoctors
},dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(MainAdmin);
There are several ways you can handle this, but you must first understand how to handle asynchronous actions that affect your dom.
Whenever a component mounts (and depending on how you've set your app up, whenever a change is made to props, state, etc), its render function is called. In your example, the component mounts, then asks the server for the list of doctors, calls render(), and then receives the list of doctors from the server. To rephrase, by the time it called the render method, it has not yet received the list of doctors from the axios call.
Apologies if you understood all of this. Now for why this.props.totalDoctorCount is returning undefined: your app's state.totalDoctorCount is not being defined until the function getTotalDoctors resolves (i.e., hears back from server). You can fix this rather simply by defining totalDoctorCount as 0 in your defaultState (where you defined doctors as an empty array).
On the other hand, do you really want users to see/think that there are a total of 0 doctors until the server responds in time? This might be a good opportunity to consider a loading component. What I like to do is right below render(), check for the existence of whatever list you need to iterate through and if it is empty, you can return a LoadingComponent (you can make this on your own and use it wherever something needs to load).
This by itself is not enough, because you don't want the page to load indefinitely in the event that you actually don't have any doctors, so this LoadingComponent should only appear if the function that is retrieving the list that it's concerned with is still 'fetching'. So perhaps you can implement three actions that are called before you fetch, after the fetch is responded to, and if there is an error.
So to outline:
1) MainAdmin mounts.
2) GetDoctors and GetTotalDoctors are called.
3) A new action isFetching is called, leaving your state as:
{
doctors: [],
totalDoctors: 0, //assuming you have added this to defaultState
isFetchingDoctors: true
}
4) MainAdmin calls render().
5) since state.doctors is empty and state.isFetchingDoctors is true, MainAdmin.render() returns your new LoadingComponent.
6) Your server responds to your axios call with the list of doctors and the totalDoctorCount (note: this will happen at different times, but for sake of simplicity, I am treating them as happening together).
7) Your success handler updates your state with the new list of doctors:
{
doctors: [1, 2, 3],
totalDoctors: 3,
isFetchingDoctors: true
}
8) MainAdmin calls render() again because of the change in state, but because state.isFetchingDoctors is still true, it will still show LoadingComponent.
8) Your second new action isFetched() is called, leaving your state as:
{
doctors: [1, 2, 3],
totalDoctors: 3,
isFetchingDoctors: false
}
9) MainAdmin calls render() again, but this time the conditions to indicate that it is no longer loading are met, and you can safely iterate through your list of doctors.
One final note: You could also set isFetching to false in your reducer as soon as you GetDoctors but I personally like to separate the asynchronous status functions into their own function to keep to the motto of every function only tasked with doing one thing.

Categories

Resources