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