Assigning props to variable in React class component - reactjs

I have a simple react component. I would like to assign a variable inside the component method to props. I've tried this method works with functional components:
class Pets extends React.component {
constructor(props) {
super(props)
}
const {dog, cat, frog} = props
// the code on the line above does not work
render() {
return (
<div>
{dog.name}
{cat.name}
</div>
)
}
}

That will not work. props is a property on the instance of the component you created with <Pets /> JSX for example. It needs to be inside the instance methods of the class Pets. It will work if you do it in the render method by const {dog, cat, frog} = this.props. props in the class body as you have now in the question is not what them expected to be.
Inside the constructor function just const {dog, cat, frog} = props will work, because here props object is received as an argument. so this.props (after the super(props) line)andprops` is same object.
Generally you unpack props where you need them, for example you need those inside the render to create some output, so you unpacked it there. I tried to explain in this answer what props means in the class body, and instance methods body, how you can access the props in different methods etc. But as xadm said, unpacking them inside the constructor by thinking you will access them later in other methods will not work due to the scope boundary, unless you store them as a property to the instance again using this.dog = props.dog. But this is an horrible idea, never do this. Just unpack them when you need any property from props object in that place only.

Related

const value between class components in React

I have a class component which renders a const. all the values needed for its evaluation are inside that component. However for purposes of splitting up and keeping the code clean, it is used in another class component. How do i connect them?
Code:
Class component1 extends React.Component
///code
render() {
const {allFacts, currentPage, factsPerPage } = this.state
const indexOfLastFact = currentPage * factsPerPage
const indexOfFirstFact = indexOfLastFact - this.state.factsPerPage
const allFactsSliced = allFacts.slice(indexOfFirstFact, indexOfLastFact) <-- THIS
}
///
export default component1
the last const, allFactsSliced, is then used in another component:
Class component2 extends React.Component
///code
render() {
const renderAllFacts =
this.state.isLoading ? <div id="loading">///</div> :
allFactsSliced.map((fact, index) => <--- HERE
{return <div>Fact # {index +1}: <br/> {fact.fact}</div>})
is this possible, good practice, or am i just needlesly complicating things and should keep everything in one component?
You can pass information into React components either by props, context, or a pure JS function or object.
So, if you want to pass allFactsSliced (or any other data) from one component to another, you have to do that by either props or context (since that particular piece of data is derived from the state of a component, you can't do it by a pure JS function or object).
If you have a parent/child relationship between these components, then you can pass derived state from the parent to the child (here it would have to be component1 to component2). If they are siblings, then you have to lift the state (see the React docs: https://reactjs.org/docs/lifting-state-up.html).
If it's more a grandparent or great-grandparent, then you can consider putting that derived state from component1 into a context and having component2 consume that context.
It's worth mentioning that you'll re-render any components that rely on that prop or context when it changes it, so it may be faster to keep it in one component. Or it might not be. Profile it and check if it matters.
But, if you want to pass a value from one component to another, it's always either as a prop or a context.

Can we access props passed to the component in a custom function

this may sound silly but I can't find a guide to this.
what I'm trying to do is changing a variable named update in parent.
and in the parent DOM do :
<Child update={this.state.update} />
and in the child instead of picking it up between render and return (with const {update} = this.props) and only being able to use it in the DOM, I'd like to pick it up in the section between the constructor and render and use it in a function there.
You can access the props to the component anywhere in the component whether it be the constructor, lifecycle functions, render or custom functions.
The only thing that you need to know is that constructor, lifecycle methods and render function are already have binding to the context of the React component, but for custom function you need to add binding yourself. Binding can be done in the constructor or by declaring the functions as arrow functions.
Check this answer on why you need to bind custom functions: Why do we need to bind function and eventHandlers in React and what is the difference between the different binding methods
For your case
<Child update={this.state.update} />
where Child could be
class Child extends React.Component {
componentDidMount() {
const {update} = this.update || {};
console.log(update);
this.somefunc();
}
somefunc = () = {
const {update} = this.update || {}; //After function is binded, you can do the same thing here too
console.log(update);
}
}
React has a lifecycle of functions called on a component: https://reactjs.org/docs/react-component.html
On startup of component you can use componentDidMount()
if you want to change state based on props change use: componentWillReceiveProps()
Otherwise if you want the result of that function to use as data for in your view (but just manipulated). Than make a seperate function also called: computed property of computed function. (because the result is computed based on current state/props). React will make sure you don't re-render/compute unnecessary.

Unable to refer to immediately destructured props in class component, do I have to use `this.props` every time?

In a stateless functional component, we can use destructured props as the function arguments:
const Blah = ({ hello, world }) {
return <div>{hello} {world}</div>
}
This gives very clean code and not only is it obvious what props are being passed, we don't have to use this.props everywhere.
Having to use this.props all the time in a class component can take up a lot of room all over the component and is not nearly as nice to use:
class Blah extends Component {
render() {
return (
<div>{this.props.hello} {this.props.world}</div>
)
}
}
My questions is, what similar approach can we take for class components so that we don't have to use this.props everywhere?
One solution I can think of would be to destructure the props in the render method, but of course you would have to do that for every method in your class should you want to use the destructured name.
Nope I'm afraid there's no way to. The functional component is essentially a render() function of a class component, the "cleaniness" is kinda the same actually (:

What exactly is a "Prop" in React?

I just started using React native on iOS to see how it feels like and I have a silly question..
I see everyone talking about "Props", whenever I read an article or a tutorial, the author uses this term a lot and it's the same in the code. For instance, in class declarations I often see constructors like :
class MyClass extends Component {
constructor(props) {
super(props);
this.state = { message: '' };
}
}
I can't find a clear explanation of what a prop is, could anyone enlighten me about that ?
props are the values that you pass down to your React component. So whenever you have a component you'll see something like this:
<MyComponent value1={value1} isTrue={true} />
In addition to the answer of Keith, below you can find the non-JSX version that uses a 'color' property.
// Output (JS):
var app = React.createElement(Nav, {color:"blue"});
React Props are read-only arguments passed from one React Component to another (down the component hierarchy).
Let's say you have two components - App and List. Then, inside App we have a list with information from developers. If we wanted to pass the array to the List component, we'd do something like this (<List list={developers} />)
import React from 'react';
const App = () => {
const developers= [
{
id: 1,
name: 'Randy'
},
{
id: 2,
name: 'Tiago Peres'
},
];
return (
<div>
<h1>Developers in StackOverflow</h1>
<List list={developers} />
</div>
);
};
const List = props =>
props.list.map(item => (
<div key={item.id}>
<span>{item.name}</span>
</div>
));
export default App;
This would be the result
Using this, we don't need to have too much information in the global scope.
If you want to know more about it, there's a great article from Robin Wieruch that i would suggest you to read.
To understand the specific case you mention, one must know some basics of React and also ECMAScript 6 (ES6). Based in content from W3Schools's React Tutorial,
A class created with a class inheritance inherits all the methods from another class.
To create a class inheritance we use the extends keyword.
You're creating a class named MyClass which will inherit the methods from the Component class.
The properties of a class are assigned inside a constructor() method
The constructor function is called automatically when the object is initialized.
The super() method refers to the parent class and so executes the parent component's constructor function.
If the component has a constructor function, the props should always be passed to the constructor and also to the React.Component via the super() method.
super(props) would call the Component constructor passing in props as the argument.
While most likely you could just use super(), using super(props) ensures this.props is set even before the constructor exits.
Even though in your case the state object has only message property, you can have as many as you like.
You can use this.state.message anywhere in the component.
Props : Props is nothing but property of component and react component is nothing but a JavaScript function. Props are immutable. You can pass props between components.You can pass props from parent component to child component directly. For passing from child to parent you need use concept of lifting up states.
class Parent extends React.Component{
render()
{`enter code here`
return(
<div>
<Child name = {"Sara"}/>
</div>
);
}
}
class Child extends React.Component{
{
render(){
return(
<div>
{this.props.name}
</div>
);
}
}

Is constructor needed for a ReactJS component class

I'm using ReactJS in Typescript. Do I need the "Constructor" code below? It works fine without it and I looked at the trans-piled JavaScript and it appears to add it in automatically anyway.
interface myProps {
children?: any;
}
class MyButton extends React.Component<myProps, {}> {
constructor(props: myProps) { //Needed ???
super(props);
}
render() {
return (<div>
<button>
{this.props.children}
</button>
</div>);
} //end render.
} //end class.
No, you don't need to.
In fact, you could write a simple component like this as a function.
const MyButton = (props) => {
return (
<div><button>{props.children}</button></div>
);
};
As mentioned in the accepted answer:
const MyButton = (props) => {
return (
<div><button>{props.children}</button></div>
);
};
This works but it's not the same - not at all. This is constructing a StatelessComponent (without state, without lifecycle-hooks, it's just a plain function, returning only the JSX or the part of the "render" function).
If you need state or lifecycle-hooks, you must extend from React.Component - like it is already done in the question.
To actually answer your question - yes constructor is needed. That's because you are extending of an existing class which is already asking for an initial property ("props") that must be given on the construct -> because it is a react class, react will call internally something like
new MyButton(props);
He will always give you the props object into the instantiated Component. Now, by extending this existing react component class, you must achieve the same - or you will end up missing your "props" object. To make it possible, that one can still pass "props" to your newly defined component, you have to define the props also on your constructor, so you have to write this:
constructor(props: myProps) { .. }
Otherwise, you can't pass anything when you call "new MyButton(props)" -> well, this will not except or bring an error, but "props" will just be "null" in your further code of "MyButton".
Last but not least - you have to call the "super" in an extended version.
super(props);
Otherwise, you won't pass the given "prop" object to the basic class which you're extending from. Here, it could work too without it, but - then "props" will be "null" in any code of "React.Component" itself.
So, yes it is needed!
Basically you can answer this question yourself by simply using a debugger - just open your web-dev tools, jump to your component code, make a breakpoint in your constructor and watch closely what is happending and what is passed ;) Then, delete the property in the constructor once.. and remove the super call once... how will it except/break apart? ;)
Update:
The other question you can always ask yourself when creating new react components: do i need state? do i need lifecycleHooks?
If one of those is yes, you'll have to extend from React.Component - because only the basic class is giving you this sugar. But as can say, no, i don't need any of those - always go with a StatelessComponent:
const MyComp = (props) => (
<div></div>
)
And try to avoid local component states too - you can do much better with one global state trough react-redux and selectors ;)
Constructor and Super are no longer necessary in react. State can be defined without a constructor and lifecycle hooks also work fine. This is a result of Babel transpiling the components that way: http://2ality.com/2017/07/class-fields.html
In traditional ES6 this is currently not the case.
Today, the constructor is needed only when you must initialize a component with a state from props.
import React from 'react'
class AChildComponent extends React.Component {
constructor(props){
super(props)
this.state = {
myState: props.myStateFromProps
}
}
render(){
return(
<div>
<p>{this.state.myState}</p>
</div>
)
}
}
export default AChildComponent

Resources