React etiquette calling components

is it ok practice to call components from other components in react, rather than the render?
just feels wrong but components both using state not directly sharing data without telling this.state. so i think why not

is it ok practice to call components from other components in react, rather than the render?

Iā€™m not sure what you mean by ā€œcall componentā€ You nest them or use them. You should not be directly calling a render method.

just feels wrong but components both using state not directly sharing data without telling this.state. so i think why not

The state of each component is its own. They donā€™t share state, not directly. You can pass it as props, or share it with the context API or some state management tool (e.g., redux) but they donā€™t share state - there is no global state, just local to each component.

Iā€™m still not sure Iā€™ve understood. If that didnā€™t answer your question, could you give and example?

sorry, my style of learning seems to be to forget everything I just read about when I start the projects/practice stuff.

I was writing up some action creators inside the class component and just carried on writing every component into the class component, but maybe some need moving.
Iā€™ll show my code so far, but the commented out pause() component was triggering the iterator() action, rather than render, hence my question.
(or [https://codepen.io/camalDan/pen/eYeOewb] )

function calcMinutes(secs){
  let RemainerMins = secs % (60 * 60);
  let answerMinutes = Math.floor(RemainerMins / 60);
  return answerMinutes
}
function calcDisplaySeconds(secs){
  let RemainerMins = secs % (60 * 60);
  let RemainerSecs = RemainerMins % 60;
  let displaySeconds = Math.ceil(RemainerSecs);
  return displaySeconds
}
class CounterDowner extends React.Component {
  constructor() {
    super();
    this.state = {
      minutes: 25, 
      seconds: 1500,
      displaySeconds: 0,
      pausey: true,
    };
    this.timer = null;
    this.iterator = this.iterator.bind(this);
    this.countDown = this.countDown.bind(this);
    this.plusMin = this.plusMin.bind(this);
    this.minusMin = this.minusMin.bind(this);
//    this.pause = this.pause.bind(this);

  }
/*
  componentDidMount() {
    this.countDown(this.state.seconds);
    this.setState({
      minutes: this.state.minutes,
      seconds: this.state.seconds,
      displaySeconds: this.state.displaySeconds,
    });
  }
*/
  iterator() {
       this.setState((prevState)=>({
      pausey: !prevState.pausey,
    }));
    if(this.state.pausey) this.timer = setInterval(this.countDown, 1000)
  }
 /* 
  pause() {
    this.setState((prevState)=>({
      pausey: !prevState.pausey,
    }));
    if(this.state.pausey) this.iterator();
  }
*/
  countDown() {
    let nextSec = this.state.seconds - 1;
    this.setState({
      minutes: calcMinutes(nextSec),
      seconds: nextSec,
      displaySeconds: calcDisplaySeconds(nextSec),
    });
    if(this.state.pausey){clearInterval(this.timer);}
    if (nextSec <= 0) {
      clearInterval(this.timer);
    }
  }
  
  plusMin() {
      if(this.state.seconds < 3540){
        this.setState((prevState)=>({
          seconds: prevState.seconds+60,
          minutes: calcMinutes(prevState.seconds+60),
        }));
      }
    }
  minusMin(){
      if(this.state.seconds > 60){
        this.setState((prevState)=>({
          seconds: this.state.seconds-60,
          minutes: calcMinutes(this.state.seconds-60)
        }));
      }
    }

  render() {
    return(

      <div>
        <div className='setters'>
          <button  className='setButsLeft' onClick={this.plusMin}>+ </button><button className='setButsRight' onClick={this.minusMin}> -</button><br/>
        </div>
        <div  className='centr'>
          <h1 className='nums'>{this.state.minutes} : {this.state.displaySeconds}</h1>
        </div>
        <div className='controls'>
          <button className="setControlLeft" onClick={this.iterator}><i className="fa fa-play"></i> / <i className="fa fa-pause"></i></button>
       {/*}   <button className='setControlMid' onClick={this.iterator}><i className="fa fa-pause"></i></button>*/}
          <button className='setControlRight'><i className="fa fa-refresh"></i></button>
          
        </div>
      </div>
    );
  }
}
ReactDOM.render(<CounterDowner/>, document.getElementById('app'));

actually i found an example of what i meant in the given solution (not sure why we have access to a solution for projects but i donā€™t use it generally) :
Itā€™s from the example 25+5 clock and timerControl() calls?/triggers? the beginCountDown() method I believe. So whatever that is referred to as is acceptable I guess?

 timerControl() {
    if (this.state.timerState === 'stopped') {
      this.beginCountDown();
      this.setState({ timerState: 'running' });
    } else {
      this.setState({ timerState: 'stopped' });
      if (this.state.intervalID) {
        this.state.intervalID.cancel();
      }
    }
  }
  beginCountDown() {
    this.setState({
      intervalID: accurateInterval(() => {
        this.decrementTimer();
        this.phaseControl();
      }, 1000)
    });

src: https://codepen.io/freeCodeCamp/pen/XpKrrW?editors=0010

I was writing up some action creators inside the class component and just carried on writing every component into the class component, but maybe some need moving.

Yeah, you definitely want to break things up. Codepen is a little weird for React in that you canā€™t break things into separate files. But each component should at least be its own class/function. But Iā€™m not really seeing what youā€™re saying. For example, I donā€™t see any action creators.

Some thoughts on what Iā€™m seeingā€¦

You donā€™t need to bind your class methods if you use arrow functions.

This:

  iterator() {
       this.setState((prevState)=>({
      pausey: !prevState.pausey,
    }));
    if(this.state.pausey) this.timer = setInterval(this.countDown, 1000)
  }

is worrisome. There is no guarantee that that setState will be finished before that if statement is evaluated. You can put that logic first or put it in a callback as a second parameter to the setState.

But Iā€™m still not clear what your question is.

sorry, despite going over the course material more than once i find myself needing reminding the basics. Iā€™m not trying to incorporate redux yet, so Iā€™m not talking about ā€˜action creatorsā€™ but ā€˜componentsā€™.
your responses are probably more what I actually need to hear, rather than any answer to my dumb questions.
So basically Iā€™m struggling to decide what should be within the main(?) class component, what should have itā€™s own class component, and what should be a simple const component.

Is this in regards to a stateless functional component? meaning it doesnā€™t change state but only returns render from data/logic?

(Iā€™ll set topic to solved, just to give my incoherent ramblings a low priority for your busy whizzos)

100% normal.

So basically Iā€™m struggling to decide what should be within the main(?) class component, what should have itā€™s own class component, and what should be a simple const component.

Yeah, that can be a struggle, knowing how to divide things up. It takes practice. In the beginning, I think that thinking visually, about the screen, is a great place to start.

As to class vs functional component, things are a little different in React now, but in this point of Reactā€¦ The only things that should be class components are things that need state or lifecycle methods - everything else should be functional components.

You donā€™t need to bind your class methods if you use arrow functions.
Is this in regards to a stateless functional component? meaning it doesnā€™t change state but only returns render from data/logic?

No, FCs donā€™t have state (at least not in this version of React).

When this lesson was written, you had to bind this to your class methods in the constructor. Iā€™m saying that if you make it an arrow function, then you donā€™t have to because the method will just inherit the classā€™ this. Declare it like this:

iterator = () => {

Or donā€™t. Either works.

1 Like

so you mean the UI?
so setting the ā€˜breakā€™ timer has itā€™s own UI element, so itā€™ll have itā€™s own component.

but as the code is similar to the ā€˜sessionā€™ timer code for running the ā€˜breakā€™ timer, and I am going to use the same UI element for the display clock, I may use that component (main) to run the ā€˜breakā€™ timer (as opposed to setting it), and therefore the ā€˜break timer settingā€™ component would need to alter state?
and therefore should be a class component?

(sorry about number 2, I barely understand my own words, lol) But are my plans sensible here?

Sure, that is one way to think of it.

but as the code is similar to the ā€˜ session ā€™ timer code for running the ā€˜ break ā€™ timer, and I am going to use the same UI element for the display clock, I may use that component (main) to run the ā€˜breakā€™ timer (as opposed to setting it), and therefore the ā€˜ break timer setting ā€™ component would need to alter state?
and therefore should be a class component?

If I understandā€¦

Yes, if I have two clocks, I would create a generic clock component.

Should it be a class or FC. It needs access to its parentā€™s state, not its own state. It probably doesnā€™t need its own state.

Remember that in vanilla React, there is no app state, only state for the individual components. So, the parent will pass its state into the child. And if the child to affect the parentā€™s state, then the parent will also need to pass a callback function.

This can be a confusing pattern, so I once created this pen to help people understand. This pattern can get very messy with large apps - thatā€™s where things like redux come in handy. But itā€™s important to understand this pattern first.

To be clear, if I understand, no, they should not be classes because they donā€™t have their own state and donā€™t need lifecycle methods. But if it makes things easier for now, you can just make everything a class and change it later if needed.

1 Like

that pen is just what i needed, thanks.

so
child 1: a stateless functional component (can use state frm parent to render something, but wont change state)
child 2: a stateful fuctional component where parents state is changed
child 3: altho useState is skipping a little ahead for me, this could be a class as it has, and renders, itā€™s own state. but useState is a hook which means it can remain a stateful functional component but the declared variable is preserved between function calls, like state.

but also

ā€¦but i could also put logic into the child component. If the logic is specific to that child, would that be preferable?

(thanks, mate. I shall endeavour to put that into practice without bothering the forum for the rest of the day, at least :smile:)

No, child two is a stateless FC. At the point in Reactā€™s evolution, all FCs are stateless. They donā€™t have state until we get to hooks (which you havenā€™t learned yet). It has access to the parentā€™s state but has no state of its own. It doesnā€™t even know or care that those values are some other componentā€™s state. To it, they are just props.

child 3: altho useState is skipping a little ahead for me, this could be a class as it has, and renders, itā€™s own state.

Yes, that is skipping ahead. That is a stateFUL FC, using a hook. In modern React, we donā€™t use classes much as FCs can have state. This didnā€™t exist when the lesson was made. So ignore this for now. Thatā€™s fine, you need to understand classes.

ā€¦but i could also put logic into the child component. If the logic is specific to that child, would that be preferable?

Iā€™m not sure what you mean by ā€œlogicā€ here. Do you mean keeping the state there? Then how would the parent have access? This is a pattern called ā€œlifting up stateā€, moving it to the common ancestor of all the components that need it. Again, this gets messy, which is why people like things like redux. But even with that, you still need to understand lifting up state.

Ah. stateless and stateful refer to a components own state, not parents, including when it changes it. ok.

No, I meant the JS functionality. Refering to the difference between passing in a (callback?) function as a prop, or performing itā€™s own JS (which i called logic) before the return.
e.g. child 2 has increment = () => this.setState(oldState => ({ count: oldState.count + 1 })) passed to it, but if it were specific to child 2 this function could be written into child 2.?

Sure, a child can have its own state, separate from an ancestorā€™s state (that the child sees as props). There may be cases where you want this. Even with something like redux there are situations where you want a component to have and manage its own state.

1 Like

Iā€™ve finished (to my limited standards) the JS / JSX functionality of that project and I would appreciate any feedback just on the basic react structure. where the setState functions are located, how all others are outside the parent component, including at least one of each type class and FC. I couldnā€™t get the onClick functionality to work in the reset component when i tried to make it an FC, but it worked as a class.
(I know there are other things, like correcting for drift in the timing and lots of CSS libraries begging for a run out. at the moment itā€™s just the basic react structure/functionality Iā€™m concerned about. )

https://codepen.io/camalDan/pen/eYeOewb?editors=0011

1 Like

OK, let me do a code review. Keep in mind that I can be kind of nitpickyā€¦

All in all, things look pretty good. A few observationsā€¦

function calcMinutes(secs){
  let RemainerMins = secs % (60 * 60);
  let answerMinutes = Math.floor(RemainerMins / 60);
  return answerMinutes
}

Why are those ā€œletā€? In general, default to ā€œconstā€. The only time you need to use ā€œletā€ is if you are going to need to reassign the variable. And why is ā€œRemainerMinsā€ in PascalCase? Thatā€™s usually reserved for components, classes, modules, and enums. This should be camelCase.


let styl = ''

First of all, thatā€™s a terrible variable name. Secondly, if this is for a specific component, this should be in that component.


  countDown=()=> {
    
    let nextSec = this.state.seconds - 1;
    this.setState({
      minutes: calcMinutes(nextSec),
      seconds: nextSec,
      displaySeconds: calcDisplaySeconds(nextSec),
    });

That should be a functional setState because it is based on the previous state, even if hidden in a variable. And the same thing a few lines later.


iterator = () => {

ā€œiteratorā€ has a specific meaning in JS, I would avoid that name to avoid confusion.


Avoid cryptic names like ā€œplusSnozā€. Assume that the person reading your code does not know what you are thinking.


  resetter = () => {
    this.setState({
      minutes: 25, 
      seconds: 1500,
      displaySeconds: 0,
      pausey: true,
      snoozeTime: 300, 
      snoozeInput: 5, 
      snooze: false,
    })

Rather than write out that object here and in the constructor, store it in a constant so you only have to write it once.

if(this.state.snooze == false){styl='centr'}else{styl='centrSnooze'}

This could be cleaner as:

styl = this.state.snooze ? 'centrSnooze' : 'centr'

but the variable should be declared here and probably as a const.


resetterFunc

Naming variables is tough. I donā€™t like this name because you should not have to add ā€œfuncā€ to it. A common practice is to name your functions as action verbs, so ā€œresetā€. Another is to name booleans starting with ā€œisā€ (or ā€œshouldā€ , ā€œcouldā€, ā€œhasā€, etc.) Then you read the variable and instantly know what it is. But yeah, sometimes naming variables is tough. But when done well, your code almost reads like a story.


class ClockSet extends React.Component {     //THIS WONT WORK AS FUNC COMP. ONLY CLASS. DUE TO ONCLICK!?

No, that 100% should be an FC. Show me what youā€™ve tried.


const audio = () => {

This is a component, it should be PascalCase.


But still, the basic ideas seems right. Itā€™s mainly a bunch of nitpicky stuff.

That was a bunch of technical things. Later Iā€™ll try to look at style.

Looking at this in more of a ā€œthinking in Reactā€ veinā€¦

        <div  className={styl}>
          <h1 className='nums'>{this.state.minutes} : {this.state.displaySeconds}</h1>
        </div>

Do you need that div? I mean, could you apply that extra class to the h1?


I would have a generic component that handles the break length and session length. The you pass in a label and callback functions. I mean, you could go even deeper and have generic buttons for the time adjust. That may seem silly on an application thus small, but it is part of thinking like a React developer.


Yeah, I was able to get ClockSet to work with a FC. Remember that there is no this.props, itā€™s now ā€¦


<div id="container"><div id="app"></div></div>

I would have put ā€œcontainerā€ in my React code. I like to handle everything there.

I think the problem is Iā€™ve displayed minutes and seconds in seperate elements and treated them seperately throughout, which I have to change a bit for passing tests, so Iā€™ll implement as you suggest after coding that.

Ah! Good point. Except for the ā€˜few lines laterā€™ bitā€¦

this.setState({
        snooze: true,
        seconds: this.state.snoozeTime,
        minutes: this.state.snoozeInput,
      });

I donā€™t see previous state in assignments.

canā€™t figure out how to declare as const and assign hereā€¦ (clockBackgroundColor was styl before)ā€¦

  render() {
  // const clockBackgroundColor = this.state.snooze ? 'centrSnooze' : 'centr' // () => {}
    this.clockBackgroundColor = this.state.snooze ? 'centrSnooze' : 'centr'

ā€¦although it works like this.

baffled as to why changing to PascalCase causes <ReactAudioPlayer to become unrecognised.

Itā€™s ok, I had made simple sytax error to pass props. Fixed now.

Got a feeling StartPauseReset could be FC but wanted to use a class.

Thanks a lot for all your input. That was one of those where at first sight I had no idea what to do. I feel like Iā€™m getting it now and some of the methods start to make sense.
new file is here:
https://codepen.io/camalDan/pen/gOXbxQW?editors=0010
ā€¦although youā€™ve helped me a lot already and Iā€™ll move onto test passing/CSS stuff later today.

It has state in there. But it is a different section of state - maybe youā€™re right.


canā€™t figure out how to declare as const and assign hereā€¦ ( clockBackgroundColor was styl before)ā€¦

That would depend on how youā€™re consuming it. There is no reason why that would have to be stored on the class.


baffled as to why changing to PascalCase causes <ReactAudioPlayer to become unrecognised.

There already is an HTML tag <audio> so I would guess that before it wasnā€™t using your component. Now it is and it sees that that module isnā€™t defined. Because you imported it as camelCase. When I change the import to PascalCase, the error goes away.


Got a feeling StartPauseReset could be FC but wanted to use a class.

FCs are smaller and faster. And less typing. Always use an FC if you can.


That was one of those where at first sight I had no idea what to do. I feel like Iā€™m getting it now and some of the methods start to make sense.

Trust me, we all remember. And React is such a weird thing when you start out.

Good luck. Let us know if you run into trouble on the rest of it.

1 Like

whoops! yes, it would.

yes, i didnā€™t understand the audio part, did a bit of copy-paste coding :face_with_hand_over_mouth:. figuring it out now.

Thanks, again.

1 Like