Why React?
Virtual DOM 提高了操作 DOM 的效率,为了高性能。本质上来说,React 所抽象出来的 Virtual DOM
能够实现对 DOM 结构的只更新,不读取的特性。其中 DOM-Diff
算法是 React 效率的重要保障。自然也就赢在了「最小化的重绘」,对 DOM 进行了必要的最少更新。
- VirtualDOM 核心算法:Reconciliation Algorithm,关键要素在于 o(n^3) => o(n) 的算法复杂度,在于启发式的,使用
key
/type
的机制做性能优化。
- Focus on View & UI,不干涉数据流层等其他方向,相比起大框架,身材上具有优势,而且易于扩展和灵活组合,其余能力通过社区和 生态 支持
- Components 思想,而不是
HTML Fragments
,组件化思想,后能够很好地提高代码的 复用性 以及 维护性 - Declarative API Design,描述式编程范式
- Functional Support,函数式声明组件支持,实现比较优雅
Process of design a React view
- Break the UI into a component hierarchy
- Build a static version in React with props
- Identify the minimal (but complete) representation of UI state. Figure out what the absolute minimal representation of the state of your application needs to be and compute everything else you need on-demand.
- Identify where your state should live
- Identify every component that renders something based on that state.
- Find a common owner component (a single component above all the components that need the state in the hierarchy).
- Either the common owner or another component higher up in the hierarchy should own the state.
- If you can’t find a component where it makes sense to own the state, create a new component simply for holding the state and add it somewhere in the hierarchy above the common owner component.
- Add inverse data flow.
Component Class and React
see Two category of components.
- Container Component Class
- Pure Component Class
Components are Just State Machines.
React thinks of UIs as simple state machines. By thinking of a UI as being in various states and rendering those states, it’s easy to keep your UI consistent.
In React, you simply update a component’s state, and then render a new UI based on this new state. React takes care of updating the DOM for you in the most efficient way. (This is ensured by the technology named Virtual DOM)
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.
Attention: In React, data flows from owner to owned component through props as discussed above. This is effectively one-way data binding: owners bind their owned component’s props to some value the owner has computed based on its props or state. Since this process happens recursively, data changes are automatically reflected everywhere they are used.
When designing interfaces, break down the common design elements (buttons, form fields, layout components, etc) into reusable components with well-defined interfaces. That way, the next time you need to build some UI you can write much less code, which means faster development time, fewer bugs, and fewer bytes down the wire.
Ref
Ref 允许在 render()
方法之外,保持对一个 DOM Element 或者对象的引用。
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.focus = this.focus.bind(this);
}
focus() {
// Explicitly focus the text input using the raw DOM API
this.textInput.focus();
}
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in this.textInput.
return (
<div>
<input
type="text"
ref={(input) => { this.textInput = input; }} />
</div>
);
}
}
another way to use ref:
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
Key
ReactElement 的唯一标识符。改变之后会导致节点强制渲染。相反之,不变化则会保留组件,不会在 DOM 中进行变更操作。使用循环创建的子元素应该携带 key
。
Props and States
This is all about the data-flow.
- Mutable variable should be placed in the Component for state, static for props
- Props are for communications between elements
- Props are Read Only, do not try to modify the props inside the components
- Prefer to use
PropTypes
to validate the props - Do remember to use
setState()
instead ofthis.state = 'xxx'
Animations:
- use
refs
for canvas elements - use
class
for CSS animations - use
requestAnimationFrame()
to achieve the fluent rendering
Core API
- Know basic life-cycle methods in life time.
- Know the
prop-types
. Proptypes Details. Use typescript can achieve the same - Know typcial event system.
- Difference between
React.Component
andReact.PureComponent
andReact.FC
… - Know React
Hooks
- Know React
Suspense
- Know React
Context
ServerSide Rendering
Next.js
Function Component
Why?
- less code, more clear structure
- easy to read and test
- naturally separate the logic and view through hooks
- performance boost
High Order Function
- HighOrder Props
function logProps(WrappedComponent) {
return class extends React.Component {
componentWillReceiveProps(nextProps) {
console.log('Current props: ', this.props);
console.log('Next props: ', nextProps);
}
render() {
// Wraps the input component in a container, without mutating it. Good!
return <WrappedComponent {...this.props} />;
}
}
}
- RenderProps
// If you really want a HOC for some reason, you can easily
// create one using a regular component with a render prop!
function withMouse(Component) {
return class extends React.Component {
render() {
return (
<Mouse render={mouse => (
<Component {...this.props} mouse={mouse} />
)}/>
);
}
}
}
Error Boundaries
- know how to use
getDerviedStateFromProps()
- know
componentDidCatch
- konw React 15’s
tryRender()
way
Context
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
// Theme context, default to light theme
const ThemeContext = React.createContext('light');
// Signed-in user context
const UserContext = React.createContext({
name: 'Guest',
});
class App extends React.Component {
render() {
const {signedInUser, theme} = this.props;
// App component that provides initial context values
return (
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={signedInUser}>
<Layout />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
}
function Layout() {
return (
<div>
<Sidebar />
<Content />
</div>
);
}
// A component may consume multiple contexts
function Content() {
return (
<ThemeContext.Consumer>
{theme => (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
}
Hooks 则对应:
const contextProps = React.useContext(React.createContext('theme', { themeType: 'dark' }));
Fiber
- Use Fiber and support
async rendering
to avoid block main thread. see A look inside ReactFiber. - New render types: fragments & strings.
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
componentDidCatch
to catch react’s rendering error.portalRendering
inside ReactComponent.
render() {
// React does *not* create a new div. It renders the children into `domNode`.
// `domNode` is any valid DOM node, regardless of its location in the DOM.
return ReactDOM.createPortal(
this.props.children,
domNode
);
}
- Support custom DOM attributes.
Ref => 深入理解 ReactFiber 架构
Hooks
What is hook?
Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks don’t work inside classes — they let you use React without classes.
When to use hook?
If you write a function component and realize you need to add some state to it, previously you had to convert it to a class. Now you can use a Hook inside the existing function component.
Hook types?
- Basic Hooks:
useState
,useContext
,useEffect
- Other Hooks:
useReducer
,useCallback
,useMemo
,useRef
… series
Hook demo:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
document.title = `You clicked ${count} times`;
});
// DIY hooks
const locale = useContext(LocaleContext);
const theme = useContext(ThemeContext);
const [todos, dispatch] = useReducer(todosReducer);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
// Accepts a context object (the value returned from React.createContext)
// and returns the current context value for that context.
const value = useContext(MyContext);
// Show a label in DevTools next to this Hook
// e.g. "FriendStatus: Online"
useDebugValue(isOnline ? 'Online' : 'Offline');
// The signature is identical to useEffect,
// but it fires synchronously after all DOM mutations.
useLayoutEffect(() => {});
// useImperativeHandle customizes the instance value
// that is exposed to parent components when using ref.
useImperativeHandle(ref, createHandle, [deps]);
// customizes the instance value that is exposed
// to parent components when using ref.
const refContainer = useRef(initialValue);
// will only recompute the memoized value
// when one of the dependencies has changed.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
The state of these components is completely independent. Hooks are a way to reuse stateful logic, not state itself. Building your own Hooks lets you extract component logic into reusable functions.
Custom hooks example:
import React, { useState, useEffect } from 'react';
// define a hook
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
// use a hook in two different component function
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}
For Real Practice used in Umi.js
Suspense
微服务的动态 Load 封装 Ref => 文档
- Waiting for loading components
- Waiting for loading data or async API
Use conditions: Ref => doc
Test
- jest solution will be fine in the community
Ref
官文:
Facebook Official Docmentation
原理解析: