Can I rearrange passed data in a presentational component - reactjs

Your answers have highlighted an oversight on my part. I was taking this pattern container/presentational way too seriously and this made me realize that we could do without <Component />.
Say I have two components, <ComponentContainer /> and <Component /> and the latter renders a <Table /> component. For the sake of an example, I use Table from Ant Design.
Now, <Table /> is expecting a property dataSource with the following shape:
const dataSource = [
{
key: '1',
name: 'Mike',
age: 32,
address: '10 Downing Street',
},
{
key: '2',
name: 'John',
age: 42,
address: '10 Downing Street',
},
];
Where should I initialize this variable? Do I have to set it in ComponentContainer and pass it down to <Component /> which just passes it further down to <Table> I initially passed down some unformatted data to <Component />, say (note: the shape might also be something completely different):
const data = {
{
name: 'Mike',
age: 32,
address: '10 Downing Street',
},
{
name: 'John',
age: 42,
address: '10 Downing Street',
}
}
and then declared and set that dataSource variable in <Component /> using this data:
const { data = [] } = props
const dataSource = data.map((pieceOfData, i) = > ({
...pieceOfData,
key: i
}))
<ComponentContainer > is not supposed to know that <Component /> is using a <Table /> so for me, it was ok to pass down some unformatted data to shape it then as needed further down the component tree even though we are in a presentational component. But I was told otherwise so I don't know. Is it really bad to do anything else than rendering?

This is known as prop-drilling, a process you go through to pass your data down in the React component tree. While it's not a bad pattern, there are some issues when trying to use it from such top-level components. Usually we want to keep logical pieces together and a clear distinction between presentational and logical components.
If you want to read more about it, I highly suggest Kent C. Dodds text on prop-drilling. The text has the potential issues and how to go around it, like using state management or React's Context API.

I recommend reading the beginning of this article by Dan Abramov https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
It used to be that everyone lived and died by the presentational and container component idea and prop drilling. I tend to disagree with that model. I believe that the component logic and information should live as close as possible to where it's being used. It makes it easier for me to read and understand what code is doing if I don't have to constantly check back up 2 files to see what is being passed down. As stated in the other answer by Inacio there are good ways around this issue especially with the use of hooks.

Related

Is there a way to have a select and creatable hybrid?

I have been using the select from react-select for some time. So far, only with predefined options, without any functionality for adding any other option/s.
As far as I could read up and figure out, there is also something called creatable, which is exactly doing that. But it doesn’t allow my to predefined/static lists, as far as I could see.
I assume both have to be implemented to get either functionality, or is there a way or prop to just stick one of them?
Edit:
Maybe I didn’t emphasis to enough on the static part. Basically, I would like to have one component that has a prop like: “canAddOptions: bool”. To either allows to add values or not. As far as I can understand, I have to implement both to get this..?
I'm also using similar approach in my application, where I'm rendering static list as options and it should work as a creatable select.
As per the problem statement, you can use isValidNewOption={() => false} to make creatable as normal select.
Try something like below:
import CreatableSelect from 'react-select/creatable';
<CreatableSelect
isMulti
isValidNewOption={() => false} // You can apply condition here as per the prop you will get.
options={[
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' },
{ value: 'three', label: 'Three' },
]}
/>

How do I render a list or table of my own elements with react-window?

I have an array of thousands of objects, like
const people = [
{ name: "Alan", age: 36, score: 103428 },
{ name: "Belinda", age: 40, score: 1482822 },
{ name: "Carol", age: 51, score: 78492391 },
...
];
I want to display a table where each person object is a row, but there are so many of them and their score field updates every few seconds, and it bogs the user's machine down.
This seems the perfect opportunity to try out react-window. Only say 20 of these objects will be onscreen at any moment, so I'll just display and re-render the ones that are in the viewport right now.
But I just can't make sense of the react-window examples or documentation. Here's the example it gives for a fixed-size grid:
const Cell = ({ columnIndex, rowIndex, style }) => (
<div style={style}>
Item {rowIndex},{columnIndex}
</div>
);
const Example = () => (
<Grid
columnCount={1000}
columnWidth={100}
height={150}
rowCount={1000}
rowHeight={35}
width={300}
>
{Cell}
</Grid>
);
There's some kind of magic happening with how a FixedSizeGrid renders its children but I don't know what it is, and I don't know how I could replace Cell with a component of my own. Where are the style, columnIndex and rowIndex props coming from? I'm reading the source code and can't figure that out. It's not mentioned anywhere that you can give an array/collection to one of the react-window components so how do you map an array to one? The only way I can see to do it is by indexing into my people array, but that feels... wrong? Wouldn't that lead to sorting becoming very expensive for example?

Highcharts with React Legend placement and more

so I've recently introduced myself to Highcharts and I did create a hardcoded dummy chart on my app. However I'm having issues with mainpulating the placement specifically of the LEGEND circles. So here's the Link i drew code+inspiration from :
https://github.com/whawker/react-jsx-highcharts/blob/gh-pages/examples/Combo/App.js
And here's some of my code :)
render() {
const pieData = [
{
name: "Jane",
y: 17
},
{
name: "John",
y: 13
},
{
name: "Joe",
y: 20
},
{
name: "Ivan",
y: 50
}
];
return (
<HighchartsChart>
<Legend />
<YAxis id="number">
<PieSeries
id="total-consumption"
name="Total consumption"
data={pieData}
center={[300, 120]}
size={255}
showInLegend
/>
</YAxis>
</HighchartsChart>
);
so basically yeah I need the legend to move from the bottom to the right side etc , oh and as well as I'm not sure how to manipulate/display the values instead of the names on the chart itself .
Thanks in advance for ANY feedback and tips,
Yours truly ,
Victor (a confused Intern still)
As far as I can see from the examples of the react-jsx-highcharts library you are using the <Legend> component has some props that allow positioning.
To e.g. align it on the right try this:
<Legend layout="vertical" align="right" verticalAlign="middle" />
The documentation seems to be more than incomplete so your best chance is to look into the examples or dig into the source yourself to see which props might help you.
In most cases the components seem to be passing configuration options given as props to Highcharts as they are:
The intention of this library is to provide a very thin abstraction of Highcharts using React components. This has been achieved by passing Highcharts configuration options as component props.
In the vast majority of cases, the name of the configuration option, and the name of the component prop are the same.

How to avoid extra rendering in react with redux

I have next object:
Book = {
id: 1,
titel: "Some Book",
sections: [
{id: 1,
titel: "Section Titel",
pages: [
{id: 1, content: "Some text"},
{id: 2, content: "Some text"},
{id: 3, content: "Some text"}
]
},
{id: 2,
titel: "Section Titel",
pages: [
{id: 1, content: "Some text"},
{id: 2, content: "Some text"}
]
}
]
}
Book object stored in Redux store (state.Book).
I have component which visualizes this Book object.
Component Book renders one or more Section components and each Section component renders Page component.
Book subscribed to Redux over connect function from react-redux and listens to store.Book, hole object.
It is clear that when titel of the Book will change then hole Book object will be re-rendered including all Sections and Pages.
There are two questions:
Will react engine really re-render Sections and Pages if only Book.titel changed? Or it will identify that other parts of the component do not changed and will not re-render them.
If it will re-render then what is the best way to avoid it? Should I subscribe Section and Page component to the Store also? But it will not solve the problem, because Book listens to hole state.Book object. Or should I subscribe Book component only to state.Book.id and state.Book.titel, then use this.context.store inside to path data to the inner components?
Thanks in advance.
Yes, React will call the render method in Sections and Pages but don't be worried about performance as those are really inexpensive operations. The Virtual DOM will abstract all the heavy operations (i.e. manipulating the DOM) minimizing the impact on performance. You can run some quick tests yourself to see how the UX is not affected at all by changes this size.
I would not recommend to prevent re-rendering (as I said in #1 it's an unexpensive operation) but if you really want to, you could use shouldComponentUpdate in the Section components. You just need to return false whenever you feel the Section or their child components don't need to render

How to specify a key for React children when mapping over an array

I have a method in a react Contact List component where I am returning another component. I have got it working but am curious if there is a better way to structure how I am using the key.
Specifically - I'm asking about this line of code from the method below (data is hard coded as sample to get started):
return <ShortContact contact={contact} key={contact.id}/>
Here is the code in context:
_getContacts() {
let contactList = [
{
id: 1,
fName: "aaa",
lName: "aaaaa",
imgUrl: "http://brainstorminonline.com/wp-content/uploads/2011/12/blah.jpg",
email: "aaa#aaaa.com",
phone: "999999999999"
},
{
id: 2,
fName: "bbbbb",
lName: "bbbbbbb",
imgUrl: "https://media.licdn.com/mpr/mpr/shrinknp_200_200/bbb.jpg",
email: "bbb#bbb-bbb.com",
phone: "888888888888"
},
{
id: 3,
fName: "Number",
lName: "Three",
imgUrl: "http://3.bp.blogspot.com/-iYgp2G1mD4o/TssPyGjJ4bI/AAAAAAAAGl0/UoweTTF1-3U/s1600/Number+3+Coloring+Pages+14.gif",
email: "three#ccccc.com",
phone: "333-333-3333"
}
];
return contactList.map((contact) => {
"use strict";
return <ShortContact contact={contact} key={contact.id}/>
});
}
ShortContact Component Render:
class ShortContact extends React.Component {
render() {
return (
<div >
<li className="contact-short well whiteBG">
<img className="contact-short-thumb" src={this.props.contact.imgUrl}/>
<p className="contact-short-name">{this.props.contact.fName}</p><br />
<p className="contact-short-email">{this.props.contact.email}</p>
</li>
</div>
);
}
}
I struggled with how to make it work and not get the warning Warning: Each child in an array or iterator should have a unique "key" prop. However I am wondering if the syntax or structure is valid and if it should be refactored.
There is nothing wrong with this code. The key is required so that react knows how to render the children nodes. In fact your implementation is exactly what react requires the programmer to do. Now the details of which key to use and such can be changed, but it looks like you have the most performant solution already.
The main requirement is that the key is unique so as long as contact.id is always unique (which if its coming from a database then it will be) then you are fine.
Alternatively you can use an index on your map for the key but I wouldn't really recommend it (i'll explain below after the code snippet).
contactList.map((contact, i) => {
return <ShortContact contact={contact} key={i}/>
});
Personally I think your approach is the best approach because it can prevent additional renders. What I mean is for instance when a new contact is returned from the server every contact row would be re-rendered because the index in the array for each contact is different (assuming you aren't treating it like a stack)... The different index with new contact data at that index would cause the re-render. Because contact.id is a static number if the data for that contact hasn't changed then react wont re-render it.
The use of a unique key is required. In your example, using the id is ideal. see the following for more information:
https://facebook.github.io/react/docs/lists-and-keys.html

Resources