diff --git a/docs/fea/react/pattern.md b/docs/fea/react/pattern.md index fcc711a..5f99073 100644 --- a/docs/fea/react/pattern.md +++ b/docs/fea/react/pattern.md @@ -14,14 +14,14 @@ group: 世界知名三大框架之一,我认为热度目前为首吧 -### 设计原则 +### iPhone 上的秒表 + +设计组件的几个原则: 1. 保持接口小,props 数量要少 2. 根据数据边界划分组件,充分利用组合 3. 把 state 往上层组件提取,让下层组件只需要实现为纯函数 -举例,iPhone 上的秒表: - ```jsx import React, { useState } from 'react'; @@ -40,7 +40,7 @@ const MajorClock = ({ ms = 0 }) => { return result; }; - return

{ms2Time(ms)}

; + return

{ms2Time(ms)}

; }; // 返回所有记次jsx @@ -65,18 +65,41 @@ const ControlButton = ({ ['normal', '#aaa'], ]); + const contStyle = { + display: 'flex', + justifyContent: 'space-around', + }; + + const btnStyle = { + width: '64px', + height: '64px', + lineHeight: '64px', + textAlign: 'center', + fontWeight: '300', + borderRadius: '99px', + border: '3px solid #b4a078', + }; + if (activated) { return ( -
- - +
+ +
); } else { return ( -
- - +
+ +
); } @@ -89,9 +112,9 @@ export default class StopWatch extends React.Component { state = { isStarted: false, - startTime: null, - currentTime: null, - spilts: [], + startTime: 0, + currentTime: 0, + splits: [], }; render() { @@ -99,6 +122,7 @@ export default class StopWatch extends React.Component { return ( +

秒表

我是一个无状态组件
; + } +} + +// 函数组件 +const Demo = React.memo(() =>
我是一个无状态组件
); +``` + ## 高阶组件(HOC) 高阶组件的几个原则: @@ -147,28 +187,158 @@ export default class StopWatch extends React.Component { 2. 结果必须是一个新的 React 组件,新组件的 JSX 部分包含作为参数的组件 3. 一般需要把传给自己的 props 转手传递给作为参数的组件 +> 一般会带 with 前缀 + +### 普通用法 + ```jsx import React from 'react'; -class Demo extends React.Component { - constructor() { - super(); - } +const getUserId = () => { + return true; +}; - render() { - const { store } = this.props; - return
艹 {store}
; - } -} +const LoginBtn = () => { + return
退出登录
; +}; -const withFuckU = (Component) => { +const ShoppingCar = () => { + return
购物车
; +}; + +const withLogin = (Component) => { const NewComponent = (props) => { - return ; + if (getUserId()) { + return ; + } else { + return null; + } }; return NewComponent; }; -export default withFuckU(Demo); +const LoginButton = withLogin(LoginBtn); +const LoginCar = withLogin(ShoppingCar); + +export default () => ( +
+ + +
+); +``` + +### 高级用法 + +借鉴上文的 withLogin,根据用户是否选择登录渲染合适的组件: + +```js +const withLoginAndLogout = (ComponentForLogin, ComponentForLogout) => { + const NewComponent = (props) => { + if (getUserId()) { + return ; + } else { + return ; + } + }; + return NewComponent; +}; + +const LoginBtn = () => { + return
登录
; +}; + +const LogoutBtn = () => { + return
退出登录
; +}; + +// 通过条件判断 退出(登录)按钮 +const TopButtons = withLoginAndLogout(LogoutBtn, LoginBtn); +``` + +### 链式调用 + +```js +// 示例 1 +const SuperX = withMethod3(withMethod2(withMethod1(x))); + +// 示例 2 +const compose = (...funcs) { + if (funcs.length === 0) return arg => arg + + if (funcs.length === 1) return funcs[0] + + return funcs.reduce((a, b) => (...args) => a(b(...args))) +} + +const hoc = compose(withMethod3, withMethod2, withMethod1) +const SuperX = hoc(x) +``` + +## render props 模式 + +示例: + +```js +const Auth = (props) => { + const userName = getUserName(); + + if (userName) { + const allProps = { userName, ...props }; + return {props.login(allProps)}; + } else { + {props.nologin(props)}; + } +}; + +// 调用 +

Hello {userName}

} + nologin={() =>

Please login

} +/>; +``` + +## 提供者模式 + +```jsx +import React from 'react'; + +const ThemeContext = React.createContext(); +const ThemeProvider = ThemeContext.Provider; +const ThemeConsumer = ThemeContext.Consumer; + +const Title = (props, context) => { + return ( + + {(theme) =>

{props.children}

} +
+ ); +}; + +const Paragraph = (props, context) => { + return ( + + {(theme) =>

{props.children}

} +
+ ); +}; + +const Page = () => { + return ( +
+ 这是标题 + 这是正文 +
+ ); +}; + +export default (props, context) => { + return ( + + + + ); +}; ``` ## 参考资料