I am trying to debug a component using Context API Consumer inside render method on browser dev tools. If i place break-point inside Consumer block, i can't print props etc. on console dynamically as this is undefined. Normally running this works fine, but while debugging only value of this is undefined. Following is sample render method of component.
componentMethod = () => {
console.log(this.props.name); //Placing breakpoint here, value is this is defined
}
render() {
return (
<div className={styles.container}>
<div>
<h4>{this.props.name}</h4>
</div>
<div className={styles.block}>
<MyComponent.Consumer>
{
({ firstParam, secondParam }) =>
<AotherComponent
firstParam={firstParam}
secondParam={secondParam}
thirdParam={this.props.name}
/>
}
</MyComponent.Consumer>
</div>
</div>
)
}
I could be related fat arrow use here, but I am able to get value of this while using break-point in componentMethod. Is there a way to bind this for Consumer block?
Try this, however, your question doesn't give enough context on what you are trying to solve. It would be better if you shared the Provider implementation as well and where you use it.
render() {
const { name } = this.props;
return (
<div className={styles.container}>
<div>
<h4>{name}</h4>
</div>
<div className={styles.block}>
<MyComponent.Consumer>
{
({ firstParam, secondParam }) =>
<AotherComponent
firstParam={firstParam}
secondParam={secondParam}
thirdParam={name}
/>
}
</MyComponent.Consumer>
</div>
</div>
)
}
It looks like you are interested in knowing what your consumer is passing down to your component during execution. There are two ways to accomplish it.
Hard Way
Let us breakdown how the consumer works (using your sample). That may help you with finding the right place to debug.
in your render() method, you have a <MyComponent.Consumer> call. The new Context Consumer API is built on the render-prop pattern.
Important thing to remember about the render-prop pattern is that: it is a function call. This function should return something which react can consider while rendering the tree.
Since it is a function call, you can put your console.log statements before your element. You will have to add an explicit return statement though.
As to why it is undefined in your method. I am assuming that the componentMethod is not a lifecycle method, so it is possible that this or this.propsis undefined based on how you are invoking that method. I do not see it invoked anywhere in your render method.
Eas(y/ier) Way:
Use react dev tools browser extension. You can look up all components by name. On clicking them you can see the props and state and even the context (as far as I remember). You can even change the values and see react react to it!
Related
Is it bad practice to define a function (like handleClick in the example below) inside a stateless component? I was told that you should avoid doing so, but I can't find anything in the documentation to confirm it. If the answer is "yes" then why is defining a function into a class instead any better?
function MiniPalette(props) {
const {classes } = props;
function handleClick() {
history.push(`palette/${id}`);
}
return (
<div className={classes.root} onClick={handleClick}>
<div className={classes.colors}>{miniColorBoxes}</div>
<h5 className={classes.title}>
{paletteName}
<span className={classes.emoji}>{emoji}</span>
</h5>
</div>
);
}
It is generally a bad practice in javascript, not in React in particular. Basically if you declare a function inside a function, every time you call the parent function it will initialize the child function as well and it is a waste of resource. For details you can also check out this: https://code.tutsplus.com/tutorials/stop-nesting-functions-but-not-all-of-them--net-22315
Viet is correct in that it's a waste of resources. A good way to look at the component tree is that you want to process data at the top and near the bottom your focus is only in rendering the data. If for example you need a way to manipulate the data and update state, I would suggest passing hooks down or diverting to useContext(). This will also keep your code cleaner and you can eventually make use higher order components for like-functions.
I have simple code, I have a component called Feed with some props.
On the main content component called Articles I map through a js object and return Feed component
Now, everyone are using an anonymous function to do so.
<div>
{data.map(()=> <Feed/>))} (sorry if the syntax a bit wrong but you get the idea
</div>
now, I took the function that returns Feed outside the map function
function createFeed (feedData) {
return <Feed props/>
}
and put it
<div>
{data.map(createFeed)}
</div>
and it workds wonder, but, thus createFeed is also a component (so I need to change the name to CreateFeed) or is this just a function that return an object to a new array created by the map function thus it's only a function and not a component?
There's no magic here.
<div>{data.map(createFeed)}</div>
Is equivalent to:
<div>{ data.map(item => createFeed(item) }</div>
Since the createFeed function returns the component without adding any logic, you can just omit it and return the component. It's all the same.
Edit:
In your case, you're merely using the function as a factory, not as a functional component, so you could argue that it doesn't need to be capitalized.
That is, if you're sure that you won't use the function as a component in Jsx, this is not a problem. If you want to use it as Jsx, this causes a problem, which is documented here: https://reactjs.org/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized
If there is no use in having a factory function, I would omit it, but in the end choice is up to you.
From React documentation.
Conceptually, components are like JavaScript functions. They accept
arbitrary inputs (called “props”) and return React elements describing
what should appear on the screen.
Considering:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
or
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Will give us the ability to do this:
<Welcome name="Luke" />;
<Welcome name="Leia" />;
to use as we wish in the DOM,
Hello, Luke
Hello, Leia
Now when people prescribe props shouldn't be changed, it would make sense the reason is in my thinking would be like the same as changing the values of attributes of an image tag?
HTML:
<img id="Executor" alt="Picture of Executor" src="/somepath/vaders-star-destroyer-executor.jpg"/>
JS:
Meanwhile in a Javascript file a long time ago in a galaxy far, far away...
var imageOfVadersStarDestroyer = document.getElementById('Executor');
imageOfVadersStarDestroyer.src = "/somepath/vaders-star-destroyer-avenger.jpg"
Because if we keeping changing an elements attribute values this can cause confusion and slower renderings?
So is the reason why the prescription is to never change props in React is because is the library is trying to make elements as predictable as possible?
Setting props outside of React is dangerous and should be avoided. Why? The main reason is that it doesn't trigger re-renders. Hence bugs and unexpected behaviour.
Re-rendering
Most of the time, props are data that is store as state in the parent component, which is manipulated by calling setState() (or the second function returned by React.useState()). Once setState() is called, React re-renders and computes what has changed under the hood, with the latest props and state. Manually assigning values to props, therefore won't notify React that the data has changed and something has to be re-rendered.
The good practice
Making props read-only allows React components to be as pure as possible, which is obviously a good practice anyway even when writing plain JS. Data won't be changed unexpectedly and can only be done so by calling setState() (You might have heard of the single source of truth, which is what React is trying to leverage).
Imagine you notice something went wrong in the app and the data shown to the end user is completely different from the source, it would be a pain trying to find out where the data has been manipulated wouldn't it? :)
never change props in React
means that you should never do this.props.name = "userName" because of React's one way data binding, props are read only, to update a component's props, you should pass a function from the parent that will do that ( in the parent ) , or dispatch an action if you're using redux, a change in the props will trigger a re-render
props is a constant in this case. You will always need it in your components.
But there is a cleaner way to write it or even omit it.
Regular way with Function Expression (same as your exemple)
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
ES6 Object Destructing - explicit
function Welcome(props) {
const {name} = pros
return <h1>Hello, {name}</h1>;
}
ES6 Object Destructing - inplicit, cleaner way
function Welcome({name}) {
return <h1>Hello, {name}</h1>;
}
And of course, you can use the class way which requires the usage of this.props.yourAttr
However, in the new version 3 of create-react-app, changed class components to functional components. You can see this exact modification on Github here.
You can need to learn more about destructing assignment in the old and good MDN linked here or an in-depth approach both array and object destructuring here.
I have been working with Redux & React for a few months. I usually always use Chrome with no issues. ( Endless bugs actually :) ).
When I started testing in Firefox I ran into an issue which I need some help with ... To know if there is a perfect way at dealing with this ...
Issue
Redux Props for MapStateToProps are not yet available when the constructor gets called, which means I cannot construct my components state in the component constructor. These props become available swiftly afterwards in the render function. At this stage, it is too late because I cannot construct state in the render function (Could somehow work that, but wouldn't be good to approach right ?).
For the moment I am using the componentWillReceiveProps and duplicating my constructor function with one exception
Constructor function
constructor(props){
super(props);
//Loads of code named A
this.state = {state:A};
}
Component Will Receive Props Function
componentWillReceiveProps (){
//Loads of code named A
this.setState({state:A});
}
There may be an issue over overwriting my state here, but for my exact case here, its only displaying data, no UI changes happen... This doesn't appear correct method either way...
I read this article
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
I am not quite sure if I understand this fully. I did experiment with it a little with no working solutions.
Ideally, I need the constructor to pause until all redux store is populated which also doesn't make sense. Props arrays could be empty.
There are discussions on Slack but none seem to address this exactly. I tried googling issue but couldn't find exact issue addressed ...
I need the mapStateToProps props to construct my state. It is looking like I won't be able to do this and will need to totally refactor code to work more solely in the render function with loads of ternary operators and/or making calls to set state from the render function before the render returns.
Any thoughts on this issue?
Daniel
Why do you think you need put the data you get from props into the component state?
As far as using the data there is no difference between the two except that you're more likely to get into trouble if you copy props to state (see link you posted).
const { A } = this.state;
const { A } = this.props;
If the data is coming via an async method then you should accommodate that in your render method.
render() {
const { A } = this.props;
if (!A) {
return <LoadingIndicator />
}
...
}
I'm trying to pass 1 node as a property of another React component like this:
render: function() {
return (
<div>
<div ref='statusCircle'></div>
<Popover trigger={ this.refs.statusCircle }></Popover>
</div>);
);
}
But in the Popover, this.props.trigger is NULL.
Is there anything wrong with my code?
How can I pass a node-ref to another React component as property?
You've misunderstood the component lifecycle in React.
See here: Link
See this fiddle. https://jsfiddle.net/uzvoruf7/
Open your console, inspect the code for the "Composite" component, and see the lifecycle hooks.
var Popover = React.createClass({
render: function() {
return (<div>This is a pop-over</div>);
}
});
var Composite = React.createClass({
componentDidMount: function() {
console.log(this.refs.statusCircle); //ok, exists.
},
render: function() {
console.log(this.refs.statusCircle); //doesn't exist, sorry.
return (
<div>
<div ref='statusCircle'></div>
<Popover trigger={this.refs.statusCircle}></Popover>
</div>
);
}
});
ReactDOM.render(
<Composite />,
document.getElementById('container')
);
"refs" come alive once the DOM has been rendered.
Therefore, it follows that inside that return statement, the dom has not been rendered yet, hence the reference is null (or all references are null so to speak).
However, inside componentDidMount, you can see that your references are available just as one would expect.
This is a common error: a possible code smell that needs refactoring. Usually (not always), passing down dom-references is indicative of an imperative thought process and is not the React way. I would suggest an improvement but I'm not aware of your use-case.
After typing this I realized it's really not an answer to the original question but instead a follow-up to your request for suggestions in your comment above. If you really don't believe it should stay, I'll delete it but it's too big for a comment, sorry.
Reference material
You must be using an old version of React, so this may not look right to you at first, but you could track that information using state in that parent component by doing
ref={ function ( element ) {
// at the top of render() put
// var self = this;
self.setState({
circleWidth: element.offsetWidth,
circleHeight: element.offsetHeight
})
}
Assuming those values change over time, you'll want to add an event listener for that change (which can be added inside that ref setup) and have it run that setState again when you need it to re-render.
As for <Popover trigger= you'll want to do something to the effect of:
<Popover trigger={this.state.circleWidth > 999} />
...where 999 is whatever your trigger value would be. If it returns true, then you render Popover. If not, you destroy it. Both situations would be handled inside Popover but will not need to touch that div
Of course, good practice in React is to do that comparison at the top of render() and place the result into a variable like isTriggered.