React Best Practice
可以通过阅读一些 react-redux-boilerplate
中的基础配置,它们的确是最佳优化和最佳实践范式。
React High Performance
- Use Chrome Profiler to debug what slow down your apps. 先准确定位,再动刀修改。
shouldComponentUpdate
to decide whether to re-render to component. 优化的特点在于:如果属性相等或者状态相等的情况下,不需要 render 自然也就避免了React
内部的VirtualDOM diff
过程,提高运算效率。 那么什么情况下适合使用呢?- Pure Components with simple props.
- Leaf Components which located deep in the rendering tree.
- If we only use
immutable data
in component props, and write the component as a pure component, we can have React use a more efficient strategy for detecting changes in the props. - Immutable data structure can reduce the render times on
componentShouldUpdate
because it can reduce the time to calculate the diff with complex objects.
- Use
pure render
method as much as possible. - Use
key
props to minify the diff of elements. - Component 的 render 里不动态
bind
方法,方法都在 constructor 里 bind 好,如果要动态传参,方法可使用闭包返回一个最终可执行函数。如:showDelBtn (item) { return (e) => {}; }
。如果每次都在 render 里面的 jsx去 bind 这个方法,每次都要绑定会消耗性能。 - 谨慎将 Component 当作 props 传入。
- Move expensive code operations to
HighLevel
component.
Server-Side Render
- React 多端同构:Server 端 / Web 端 / 移动端 …
React.renderToString()
该函数去掉了用于表示渲染位置的参数。取而代之的是一个同步运算函数的字符串。当你打算在客户端渲染 React String 的时候应该使用该方法。React.renderToStaticMarkup()
:纯服务端渲染则调用此方法。
React Tips
- Try to keep as many of your components as possible stateless. By doing this you’ll isolate the state to its most logical place and minimize redundancy, making it easier to reason about your application.
- State should contain data that a component’s event handlers may change to trigger a UI update.
- We call it Pure Render.
- If you don’t use something in
render()
, it shouldn’t be in the state. - Use
key
props will force element re-mount while key props change. - Use
shallowRender
to render one-layer React Element which is a good way to test component. - Use
this.props.children
to isolate component dependency. - Use
context
to share data among components. React has the concept of context. The context is something that every component may have access to. It’s something like an event bus but for data. A single model which we can access from everywhere.
// a place where we'll define the context
var context = { title: 'React in patterns' };
class App extends React.Component {
getChildContext() {
return context;
}
...
};
App.childContextTypes = {
title: React.PropTypes.string
};
// a place where we need data
class Inject extends React.Component {
render() {
var title = this.context.title;
...
}
}
Inject.contextTypes = {
title: React.PropTypes.string
};
- Use compose instead of inheritance to build UI.
App Structure
- Use React-Router to do the routes on the browser.
- One File, One React-Class.
React UI Component
- Keep states flat via
normoalize
method. - Keep states immutable via
Immutable.js
. - Type and prototype required.
- Use high-order component to replace the mixins methods.
Higher-order components look really similar to the decorator design pattern. It is wrapping a component and attaching some new functionalities or props to it.
Where it comes from it is not important. That’s a huge advantage because it helps us testing the component in an isolation and provides nice mechanism for mocking.
var enhanceComponent = (Component) =>
class Enhance extends React.Component {
render() {
return (
<Component
{...this.state}
{...this.props}
/>
)
}
};
export default enhanceComponent;
var OriginalComponent = () => <p>Hello world.</p>;
class App extends React.Component {
render() {
return React.createElement(enhanceComponent(OriginalComponent));
}
};
- Use Dependency Injection
// enhance.jsx
var title = 'React in patterns';
var enhanceComponent = (Component) =>
class Enhance extends React.Component {
render() {
return (
<Component
{...this.state}
{...this.props}
title={ title }
/>
)
}
};
// Header.jsx
import enhance from './enhance.jsx';
import Title from './Title.jsx';
var EnhancedTitle = enhance(Title);
export default function Header() {
return (
<header>
<EnhancedTitle />
</header>
);
}
- if a component does not own its inner state, use ES6 class to declare it, else use a function.
const Listing = ({ hello }) => (
<div>{hello}</div>
);
Listing.propTypes = {};
Listing.defaultProps = {};
// instead of using .bind
// use => function to get local variable
function ItemList(props) {
return (
<ul>
{props.items.map((item, index) => (
<Item
key={item.key}
onClick={() => doSomethingWith(item.name, index)}
/>
))}
</ul>
);
}
// or you can bind function before rendering it
class extends React.Component {
constructor(props) {
super(props);
this.onClickDiv = this.onClickDiv.bind(this);
}
onClickDiv() {
// do stuff
}
render() {
return <div onClick={this.onClickDiv} />
}
}
Decouple UI Components
- separate
render
method into several ones. - use
ReactElement
as props. - use
HighOrder Component
to wrap React Component.
// for example
const NavbarWithRouter = withRouter(Navbar);
const CommentWithRelay = Relay.createContainer(Comment, config);
const ConnectedComment = connect(commentSelector, commentActions)(Comment);
// ... you can use a function composition utility
// compose(f, g, h) is the same as (...args) => f(g(h(...args)))
const enhance = compose(
// These are both single-argument HOCs
connect(commentSelector),
withRouter
)
function withLinkAnalytics(mapPropsToData, WrappedComponent) {
class LinkAnalyticsWrapper extends React.Component {
componentDidMount() {
ReactDOM.findDOMNode(this).addEventListener('click', this.onClick);
}
componentWillUnmount() {
ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick);
}
onClick = (e) => {
if (e.target.tagName === 'A') { // Naive check for <a> elements
const data = mapPropsToData ? mapPropsToData(this.props) : {};
sendAnalytics('link clicked', data);
}
};
render() {
// Simply render the WrappedComponent with all props
return <WrappedComponent {...this.props} />;
}
}
return LinkAnalyticsWrapper;
}
HighOrder Components
Concretely, a higher-order component is a function that takes a component and returns a new component.
Whereas a component transforms props into UI, a higher-order component transforms a component into another component.
HOCs are common in third-party React libraries, such as Redux’s connect
and Relay’s createContainer
.
Data-Flow and App Structure
Use one-way direction data-flow.
- Use Redux to offer the predictable states container.
- Use React Router to related routes with React Apps.
Quality Assurance
- Enjoy the Functional way.
- Use Babel and ES2015 to write code.
- Use Linters to ensure code quality.
- Use Mocha for UNIT test.
- Use Enzyme for UNIT Test lib.
Tools Chain
- Use npm to manage modules.
- Use Webpack to load modules, resources and manage build process.
- Use Hot-Reload tech to develop React Apps.
Reference: