Data flow in React
Destructuring
Functional component
Passing data
ReactCSSTransitionGroup
Sonarqube error
ngrok TODO
Showing and hiding components or html
Less complex render functions
What to use as key
To chain or not to chain
Remember: React is all about one-way data flow down the component hierarchy.
React’s one-way data flow (also called one-way binding) keeps everything modular and fast.
Thinking in React (React docs)
Destructuring properties:
const { isFIAWidget, change, controls } = this.props;
render (
<Component
isWidget={isFIAWidget}
change={change}
type={controls.insuranceAgentType}
/>
);
Destructuring controls inside properties:
const { isFIAWidget, change, controls: { insuranceAgentType } } = this.props;
render (
<Component
isWidget={isFIAWidget}
change={change}
type={insuranceAgentType}
/>
);
- Basic component
- No state
- "Dumb" component
import './Name.scss';
import React, { PropTypes } from 'react';
const Name = () => {
return (
<div className="class-name">component</div>
);
};
Name.propTypes = {};
export default Name;
Header.json
{
"header": {
"menuItems": [],
"searchBar": {
"placeholder": "Zoeken...",
"icon": "search-2"
}
}
}
Header.jsx
<SearchBar {...this.props.searchBar} />
// or
<SearchBar
placeholder={this.props.searchBar.placeholder}
icon={this.props.searchBar.icon}
/>
// or with destructuring
const Header = ({ menuItems, searchBar }) => {
// so you can use
<SearchBar {...searchBar} />
// or
<SearchBar placeholder={searchBar.placeholder} />
}
Header.jsx
as class based component
class Header extends Component {
// stuff
render() {
const { searchBar } = this.props;
return (
<SearchBar {...searchBar} />
);
}
}
Renders a <span>
around the child. This troubles grids and layouts. But you can add a className to the ReactCSSTransitionGroup
:
<ReactCSSTransitionGroup className="o-layout">
rename this function to match the regular expression ^[a-z][a-za-z0-9]*$ (s100)
We turned this off in our project, since components should start with a capital letter:
<component />
compiles toReact.createElement('component')
(html tag)<Component />
compiles toReact.createElement(Component)
<obj.component />
compiles toReact.createElement(obj.component)
Thoughts?
TODO
if
{boolean && (
<Component />
)}
if else
{boolean ? (
<ComponentTrue />
) : (
<ComponentFalse />
)}
It says boolean, but does not have to be a boolean. Can be a string / object / whatever. It will be true
when it has a value and false
when the value is null
.
Inside the components render function:
{boolean && this.renderSpecificComponent()}
Outside the components render function is another function, called renderSpecificComponent
:
renderSpecificComponent() {
const { property } = this.props;
return (
<div>Specific stuff</div>
);
}
Splits the logic, makes it easier to read and you won't get Sonarqube complex function issues: Function has a complexity of 11 which is greater than 10 authorized.
Also, from stackoverflow:
A function in the render method will be created each render which is a slight performance hit. It's also messy if you put them in the render, which is a much bigger reason, you shouldn't have to scroll through code in render to see the html output. Always put them on the class instead.
For stateless components, it's probably best to keep functions outside of the main function and pass in props instead, otherwise the function will be created each render too. I haven't tested performance so I don't know if this is a micro-optimization but it's worth noting.
How we used to do it (this is an anti pattern):
array.map((item, index) => {
return (
<Component key={index} stuff={item} />
);
});
Why is this wrong? Because the order of your rendered components could change.
To discuss
Index as a key is an anti-pattern
How would you write this?
values = {
"question-1": "10",
"question-2": "20"
}
// no chain
const entries = Object.entries(values);
const scores = entries.map(entry => {
return parseInt(entry[1], 10);
});
const total = scores.reduce((acc, cur) => {
return acc + cur;
});
// yes chain
const total = Object.entries(values)
.map(entry => {
return parseInt(entry[1], 10);
})
.reduce((acc, cur) => {
return acc + cur;
});