Components in react not rendering, despite having a key property - reactjs

i am fairly new to React and this is my first project with Redux.
I get some data and set it in the state-tree. When my reducer ADD_PRODUCTS_TO_CART runs, my Products->render() runs, but Product->render() does not, despite having a key.
Here is a gist, it was the most basic i could boil it down to. Hope it makes sense, i've included a file that represents the state of the tree, so you can see the data structure.
https://gist.github.com/hoodweb/e4005e4f1fc95682d4dd9bf87b81fe39
TLDR: Basically the stock decrements in the statetree, but is not rendered. What am i doing wrong?
Update: I have put in console.log() in all render methods, to see what is called. When i decrease the stock of my product, the product is not called. This is most likely due to the .map(() => <Product/>) i am doing. I tried changing my key={} property to include the stock like this:
.map((obj) => <Product key={obj.ID.toString() + obj.Stock.toString()} data={obj} />)
Which seems to work. But I do know how stable this is.
Update2: It seems that if i take my data={} property at put it into seperate properties like this
<Product key={obj.ID} stock={obj.Stock} title={obj.Title} price={obj.Price} beforePrice={obj.BeforePrice}
it works. So that is my solution for now.

In render function of Product you got:
if (data.Variations) { //TODO: Variation logic
return false;
}
Because in data you got Variations param, it goes through this scope (beacause Variations is not null or undefined) and returns null instead of rendering component.
remove return false and your code should work fine.

Like #kiarashws said, whenever you return false in your render() method, it doesn't render. Make sure to not render only when you don't want to.
Is commonly see code like this:
render() {
if (props.shouldNotRender)
return null or false;
return <div>
...
</div>
}

Related

React Best Practices: Where to *not* render a component?

I came across some code in review and had a question on best practices. Here's the scenario:
I've got a Hyperlink component with a url prop. If for some reason url is falsy, Hyperlink renders null.
simplified example:
const Hyperlink = ({ url }) => {
return !url ? null : <SomethingElse url={url} />;
};
Does this logic belong in the Hyperlink component, or should it be the responsibility of the parent component to determine whether or not to render something?
example:
const MyParentComponent = ({ url }) => {
return !url ? null : <Hyperlink url={url} />
};
This keeps Hyperlink dumb, with the downside of having to sprinkle that logic in places url is optional.
I would say, as a generic rule, there is "avoid surprises", or "reduce WTFs per minute", or "explicit is better than implicit". Getting null instead of a <Link /> is well sort of a "surprise".
I think it may be somewhat similar to "pointers vs references", when a pointer can have a null value, whereas a reference can't. References are safer, because you don't need to worry about the null value. Consider passing that <Link /> component to some callback or argument. For example, SomeComponent here may be shocked by getting null:
const content = <Link>;
<SomeComponent contents={content}>
But in principle I think both approaches are fine.
If the conditional rendering is :
condition ? something : null
I prefere using:
condition && something
Since conditional rendering should be used for cases like:
condition ? something : somethingElse
Back to your question, if the Component has some heavy calculations before the return, it's common sense that you are wasting resources performing them since it won't return nothing if condition is false, so it' s better to use:
condition && <Component/>
But in most cases, especially if you have stateless components with no logic like that one, you won't experience particular differences between the two approaches, basically by doing the conditional rendering inside the component, you are just wasting a React.createElement().
I personally use
condition && <Component/>
in cases like that, if it's possible, since I find to be very semantically uncorrect for a Component to possibly render nothing. If you call your Component HyperLink, I expect it to return something, possibly a link. There are cases where you are forced to return nothing, and it's okay, but I try to avoid it.
Usually these type of checking should be done using Typescript.
Answering to your question it should depend upon your project scenario.
If you feel the url the Hyperlink component will receive can be null or undefined you can put the check in the Hyperlink component.
But if you think only in MyParentComponent the case will occur where url will be null you can think of conditionally rendering the component.

React hooks: am I doing an anti pattern? updating state in function outside the component

I am beginning to use React (hooks only), and facing a strange issue. I am trying to reproduce the problem in a small test code, but can't get it to happen, except in my full blown app. This leads me to wonder if I'm doing something really wrong.
I have an array of objects, declared as a state. I map this array to display its content. Except that nothing gets displayed (the array is filled, but nothing gets displayed). Now if I declare an un-related state, make it a boolean which flips each time my array gets updated, then my array gets displayed properly. As if, in the render phase itself, React did not detect the array's changes.
A few things:
the array gets updated by a socketIO connection, I simulate it here with a timer
I update my array OUTSIDE of my component function, BUT providing the setter function to the update function
I also create part of the render fields outside my component function (this has no effect, just for readability in my full app)
I essence, this is what I am doing:
const updateArray = (setTestArray, setTestTag, addArray) => {
setTestArray(prevTestArray => {
let newTestArray = prevTestArray.map((data, index) => (data + addArray[index]))
return newTestArray
})
setTestTag(prevTag => {
return (!prevTag)
})
}
const renderArray = (currentTestArray) => {
return currentTestArray.map((data, index) => (
<div>
testArray[{index}]={data}
</div>
))
}
function TestPage(props) {
const [testArray, setTestArray] = useState([])
const [testTag, setTestTag] = useState(false)
useEffect(() => {
let samples = 3
let initArray= []
for (let i=0; i<samples;i++) initArray[i] = Math.random()
setTestArray(initArray)
// In real code: setup socket here...
setInterval(() => {
let addArray= []
for (let i=0; i<samples;i++) addArray[i] = Math.random()
updateArray(setTestArray, setTestTag, addArray)
}, 1000)
return (() => {
// In real code, disconnect socket here...
})
}, []);
return (
<Paper>
Array content:
{renderArray(testArray)}
<br/>
Tag: {(testTag)? 'true' : 'false'}
</Paper>
)
}
This works just fine. But, in my full app, if I comment out everything concerning "testTag", then my array content never displays. testArray's content is as expected, updates just fine, but placing a debugger inside the map section show that array as empty.
Thus my questions:
is my updateArray function a bad idea? From what I read, my prevTestArray input will always reflect the latest state value, and setTestArray is never supposed to change... This is the only way I see to handle the async calls my socket connection generate, without placing "testArray" in my useEffect dependencies (thus avoiding continuously connecting/disconnecting the socket?)
rendering outside the component, in renderArray, doesn't affect my tests (same result if I move the code inside my component), but is there a problem with this?
As a side note, my array's content is actually more complex is the real app (array of objects), I have tried placing this in this test code, it works just fine too...
Thank you!
Edit: Note that moving updateArray inside the useEffect seems to be the recommended pattern. I did that in my full app. The hook linter does not complain about any missing dependency, yet this still doesn't work in my full app.
But the question is still whether what I am doing here is wrong or not: I know it goes against the guidelines as it prevents the linter from doing its job, but it looks to me like this will still work, the previous state being accessible by default in the setter functions.
Edit #2: Shame on me... silly mistake in my real app code, the equivalent of updateArray had a shallow array copy at some place instead of a deep copy.
Why adding the flipping tag made it work is beyond me (knowing the data was then indeed properly displayed and updated), but getting rid of this mistake solved it all.
I will leave this question on, as the question still stand: is placing the state update, and part of the rendering outside the component a functional problem, or just something which might mater on hide dependencies (preventing the react hooks linter from doing its job) and thus simply bad practice?
The fact is that things work just fine now with both functions outside the component function, which makes sense based on what I understand from hooks at this point.

ReactJs, strugglig again

There is something I really don't understand in reacts and sometime the behaviors seem more about bug features that what is expected.
I was testing an instantiation by array. What is strange that the first time, it work as expected.
{this.state.pma.map((Item, index) => (
<this.props.typePma
key = {index}
ref = {(child) => { child.display(Item)}}
onDelete = {() => this.onDelete(index)}
/>
))}
But if I'm just updating the data even without changing it, like:
appendNewPma(){
var newPma = this.state.pma.slice();
//newPma.push(this.props.typePma);
this.setState({pma:newPma})
}
I've get exception error on this line:
ref = {(child) => { child.display(Item)}}
It complains that child is None (TypeError: Cannot read property 'display' of null
).
But why?!!! Why the logic change when there is no change: The data are not changed, just redisplayed. Why the ref is sending me null object where it is obvious the ref should always give me the instantiated object.
Petyo has already pointed you in the direction of the docs which explain the situation you have come across, but I would suggest that you change your approach, rather than blaming the library.
The whole point of a ref is so that the parent can have a reference to the child. Ideally, these should be used as little as possible but in some cases it is unavoidable. In your case, instead of saving the ref, it looks like you are using it as a sort of broken componentDidMount.
Why not just change the child component to call its display method when it is mounted and/or updated? Additionally, you should consider whether the "display" behaviour can itself be moved into a separate component.
You are facing the caveat that the React docs explain. Your ref callback gets called twice - with the actual element and with null afterwards.

Extremely slow React list render

We are experiencing some frustrating issues with React.
We have a form, consisting from a search form and a search result list.
As seen below in the code. filter and content.
Whenever the user types in the search field, there is a debounce and a call to a rest service.
The result then populates the search result (content)
Even with as little as 15 items in the list, this is insanely slow.
it takes about 300 ms per update.
In production mode, there is no issue. only in dev mode.
Also, removing propTypes makes it much faster but still slow.
We can see that the ContactSearchResultLayout is being rendered 3 times per keystroke, while it really just should care about the result of the rest call.
What are our best bets here?
is the container component kind of pattern here wrong for our usecase, does it mean that if something in the SearchPageLayout props changes, the entire list will also be re-rendered?
We have a version that pretty much bypass React and just render item by item as they come in from the service call.
Which is super fast, but on the other hand, much less maintainable.
Is there some idiomatic way to make this work with React?
<SearchPageLayout
filter={
<ContactSearchForm
allTeams={allTeams}
allAreasOfExp={allAreasOfExp}
allResponsiblePeople={allResponsiblePeople}
allTags={allTags}
detailed={props.searchFormExpanded}
onSearchFieldBlur={() => props.setSearchFormExpanded(false)}
onSearchFieldFocus={() => props.setSearchFormExpanded(true)}
/>
}
content={
<ContactSearchResultLayout //<-- this rerenders too often
items={items.map(item => (
<ContactCard
key={item.PersonId}
areasOfExpertise={item.AreasOfExperise}
cellPhone={item.CellPhone}
city={item.City}
One reason for this as I see it, is that items is the result of a map operation and thus, causes a new array of components to be generated.
But how do we bypass this?
Thoughts?
Anonymous function will get rendered each time.
I'll create another method for creating the items:
getItems() {
return (
items.map(item => (
<ContactCard
key={item.PersonId}
areasOfExpertise={item.AreasOfExperise}
cellPhone={item.CellPhone}
city={item.City}
/>
)
)
}
<ContactSearchResultLayout
items={this.getItems()}
/>
How to check if props change and if you should re-render the code:
you can use react "shouldComponentUpdate"
https://reactjs.org/docs/react-component.html#shouldcomponentupdate
componentWillUpdate(nextProps, nextState) {
//here you can compare your current state and props
// with the next state and props
// be sure to return boolean to decide to render or not
}

react one state variable depends on multiple other states variables

I am coming from angular world. And I am still kinda new to react.
One question that I encountered is that:
In angular, we have $watch to watch one scope variables to change and update other variables. like watch B,C,D, and change of B,C,D will affect variable A
In react, I am trying to do the same thing. However, I am calling to setState(B,callbackB) to update A. A has a setState that has an impact in render
It seems like doing such works correctly for variable B. However, updating A will occur in next render cycle. And this.forceUpdate() doesn't seems work.
Is there anything that I am doing wrong?
Thanks
An example would help clarify your situation, but depending on what "updating A" entails, you could move it to your render function. E.g.
class Component extends React.Component {
handleUpdate(B) {
this.setState({B})
}
computeAFromB(B) {
...
return A
}
render() {
const A = this.computeAFromB(this.state.B)
return <div>{A}</div>
}
}
When transitioning from Angular to React, it's important to keep in mind that scope !== state. This may be helpful: https://facebook.github.io/react/docs/thinking-in-react.html
You cannot rely on setState to update instantly. Try passing the new value explicitly to setState A.
Here's my example code, I think I found an answer already.
https://jsfiddle.net/yoyohoho/Lo58kgfq/1/
in the example code in jsfiddle. The input field is a required field.
And the button should be disabled if there is nothing in the field.
The problem is that if you type something and you erase it, button is still active, until you type in 1 more key, which is next cycle.
I use input1Err to determine if formError should be disabled in checkErr()
checkErr(){
if(this.state.input1Err == false){
this.setState({formErr: false });
}else{
this.setState({formErr: true });
}
}
This is the reason that why the view change happen in next cycle. Because setState is asynchronous
I was using this.state.input1Err to determine formErr, which may yet be changed before the if statement there.
So I changed to the following closure, which solves my issue.
checkErr(){
const self = this;
(function(j){setTimeout(function(){
if(self.state.input1Err == false){
self.setState({formErr: false });
}else{
self.setState({formErr: true });
}
},10)})(self);
}
This seems be a quick fix. However, what if there is ajax call and hooked up to state.input1Err. Is there a way I can watch this variable, so when it changes complete, I can have some sort of callback?
Thanks

Resources