Maison > Article > interface Web > Introduction à la conception et au contrôle avancés de React
Le contenu de cet article est une introduction à la conception et au contrôle avancés de React. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
Contrôle – Ce concept est crucial en programmation. Par exemple, la « concurrence » entre la couche d’encapsulation « roue » et la couche de consommation métier pour le contrôle est un sujet très intéressant. Ce n'est pas différent dans le monde React. En apparence, bien sûr, nous espérons que la « roue » pourra contrôler autant de choses que possible : Parce que plus la couche d'abstraction gère de logique, moins nous devons nous soucier de choses lorsque nous appelons l'entreprise, et plus c'est pratique c'est à utiliser. Toutefois, certains modèles « n’osent pas aller trop loin ». La lutte acharnée entre la « roue » et l'entreprise pour le contrôle est très intéressante.
Dans le même temps, les capacités de contrôle sont également étroitement liées à la conception des composants : les conceptions de composants atomiques telles que les composants atomiques sont très respectées en plus du concept de composants atomiques, il existe également des composants moléculaires : Composants moléculaires. Qu’il s’agisse de molécules ou d’atomes, ils ont tous une raison d’exister pour résoudre les problèmes des entreprises.
Cet article utilisera le framework React comme arrière-plan pour parler de certaines de mes réflexions et conclusions sur le contrôle pendant le développement. Si vous n'utilisez pas React, en principe, cela ne vous empêche toujours pas de lire
Avant de commencer l'article, j'aimerais vous présenter un livre.
Depuis l'année dernière, Yan Haijing, un expert en technologie bien connu, et moi avons entamé un voyage de co-auteur. Cette année, nous avons peaufiné conjointement le livre "React State Management and Isomorphism in Practice". a enfin été officiellement publié ! Ce livre prend la pile technologique React comme noyau. Basé sur l'introduction de l'utilisation de React, il analyse les idées de Redux au niveau du code source et se concentre également sur les modèles architecturaux du rendu côté serveur et des applications isomorphes. Le livre contient de nombreux exemples de projets, qui non seulement ouvrent la porte à la pile technologique React pour les utilisateurs, mais améliorent également la compréhension globale des lecteurs dans les domaines de pointe.
Lorsque nous entrons pour la première fois dans React, la première chose avec laquelle nous entrons en contact à propos du concept de contrôle, ce sont les composants contrôlés et les composants non contrôlés. Ces deux concepts sont souvent associés aux formulaires. Dans la plupart des cas, il est recommandé d'utiliser des composants contrôlés pour implémenter le contrôle d'état, tels que les formulaires et les zones de saisie. Dans les composants contrôlés, les données telles que les formulaires sont gérées par le composant React lui-même. Les composants non contrôlés signifient que les données du formulaire sont contrôlées par le Dom lui-même. Ce qui suit est un composant non contrôlé typique :
Pour React, l'état et les entrées utilisateur des composants non contrôlés ne peuvent pas être directement contrôlés et ne peuvent s'appuyer que sur les capacités natives de la balise form pour l'interaction. Si vous changez le composant non contrôlé dans l'exemple ci-dessus en un composant contrôlé, le code est également très simple :
class NameForm extends React.Component { state= {value: ''} handleChange = event => { this.setState({value: event.target.value}); } handleSubmit = event => { alert('A name was submitted: ' + this.state.value); event.preventDefault(); } render() { return () } }
À ce stade, les valeurs et les comportements du formulaire sont contrôlés par le composant React, ce qui rend développement plus pratique.
Il s'agit bien sûr d'un concept très basique. Cela amène le sujet du contrôle. Les lecteurs sont invités à continuer la lecture.
Les exemples présentés ci-dessus sont ce que j'appelle des composants « au sens étroitcontrôlés et non contrôlés ». D'une manière générale, je pense qu'un composant totalement incontrôlé fait référence à un composant fonctionnel ou un composant sans état qui ne contient pas d'états internes et n'accepte que des accessoires . Son comportement de rendu est entièrement contrôlé par des accessoires externes et n'a pas d'« autonomie » propre. De tels composants permettent une bonne réutilisation et une bonne testabilité.
Mais dans la conception de la « roue » de l'interface utilisateur, les composants « semi-autonomes » ou « pas entièrement contrôlés » sont parfois un meilleur choix. Nous appelons cela le modèle « accessoires de contrôle ». Pour faire simple : Le composant a son propre état. Lorsqu'aucun accessoire pertinent n'est transmis, son propre état est utilisé pour compléter la logique de rendu et d'interaction lorsque le composant est appelé, si les accessoires pertinents sont transmis, il sera remis au droit de contrôle, contrôlant son comportement au niveau de la consommation de l'entreprise.
Après avoir recherché un grand nombre de "roues" d'interface utilisateur communautaire, j'ai découvert que downshift, une bibliothèque de composants écrite par Kent C. Dodds et utilisée par PayPal, adopte largement ce modèle.
Utilisez simplement un composant Toogle comme exemple. Lorsque ce composant est appelé par la partie commerciale :
class Example extends React.Component { state = {on: false, inputValue: 'off'} handleToggle = on => { this.setState({on, inputValue: on ? 'on' : 'off'}) } handleChange = ({target: {value}}) => { if (value === 'on') { this.setState({on: true}) } else if (value === 'off') { this.setState({on: false}) } this.setState({inputValue: value}) } render() { const {on} = this.state return ( <p> <input> <toggle></toggle> </p> ) } }
L'effet est tel qu'indiqué dans la figure :
Nous pouvons contrôler le changement d'état du composant Toggle via la zone de saisie (entrez "on" pour activer l'état, entrez "off" pour griser l'état), et vous pouvez également cliquer pour basculer avec la souris. À ce moment, le contenu de la zone de saisie sera modifié.
Veuillez réfléchir à ceci : pour le composant d'interface utilisateur Toggle, son état peut être contrôlé par l'appelant professionnel, ce qui facilite la consommation au niveau de l'utilisation. Dans le code métier, qu'il s'agisse d'Input ou de tout autre composant, son état peut être contrôlé et nous avons un contrôle total lors de l'appel.
En même temps, si vous ne transmettez pas la valeur des accessoires lors de l'appel du composant Toggle, le composant peut toujours fonctionner normalement. Comme suit :
<toggle> {({on, getTogglerProps}) => ( <p> <button>Toggle me</button> </p> <p>{on ? 'Toggled On' : 'Toggled Off'}</p> )} </toggle>
Lorsque le composant Toggle change d'état, il conserve son état interne pour obtenir l'effet de commutation. En même temps, il émet les informations d'état de ce composant vers l'extérieur via l'accessoire de rendu. mode.
Regardons le code source de Toggle (certains liens ont été supprimés) :
const callAll = (...fns) => (...args) => fns.forEach(fn => fn && fn(...args)) class Toggle extends Component { static defaultProps = { defaultOn: false, onToggle: () => {}, } state = { on: this.getOn({on: this.props.defaultOn}), } getOn(state = this.state) { return this.isOnControlled() ? this.props.on : state.on } isOnControlled() { return this.props.on !== undefined } getTogglerStateAndHelpers() { return { on: this.getOn(), setOn: this.setOn, setOff: this.setOff, toggle: this.toggle, } } setOnState = (state = !this.getOn()) => { if (this.isOnControlled()) { this.props.onToggle(state, this.getTogglerStateAndHelpers()) } else { this.setState({on: state}, () => { this.props.onToggle( this.getOn(), this.getTogglerStateAndHelpers() ) }) } } setOn = this.setOnState.bind(this, true) setOff = this.setOnState.bind(this, false) toggle = this.setOnState.bind(this, undefined) render() { const renderProp = unwrapArray(this.props.children) return renderProp(this.getTogglerStateAndHelpers()) } } function unwrapArray(arg) { return Array.isArray(arg) ? arg[0] : arg } export default Toggle
关键的地方在于组件内 isOnControlled 方法判断是否有命名为 on 的属性传入:如果有,则使用 this.props.on 作为本组件状态,反之用自身 this.state.on 来管理状态。同时在 render 方法中,使用了 render prop 模式,关于这个模式本文不再探讨,感兴趣的读者可以在社区中找到很多资料,同时也可以在我新书中找到相关内容。
盘点一下,control props 模式反应了典型的控制权问题。这样的“半自治”能够完美适应业务需求,在组件设计上也更加灵活有效。
提到控制权话题,怎能少得了 Redux 这样的状态管理工具。Redux 的设计在方方面面都体现出来良好的控制权处理,这里我们把注意力集中在异步状态上,更多的内容还请读者关注我的新书。
Redux 处理异步,最为人熟知的就是 Redux-thunk 这样的中间件,它由 Dan 亲自编写,并在 Redux 官方文档上被安利。它与其他所有中间件一样,将 action 到 reducer 中间的过程进行掌控,使得业务使用时可以直接 dispatch 一个函数类型的 action,实现代码也很简单:
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; } const thunk = createThunkMiddleware(); export default thunk;
但是很快就有人认为,这样的方案因为在中间件实现中的控制不足,导致了业务代码不够精简。我们还是需要遵循传统的 Redux 步骤:八股文似的编写 action,action creactor,reducer......于是,控制粒度更大的中间件方案应运而生。
Redux-promise 中间件控制了 action type,它限制业务方在 dispatch 异步 action 时,action的 payload 属性需要是一个 Promise 对象时,执行 resolve,该中间件触发一个类型相同的 action,并将 payload 设置为 promise 的 value,并设 action.status 属性为 "success"。
export default function promiseMiddleware({ dispatch }) { return next => action => { if (!isFSA(action)) { return isPromise(action) ? action.then(dispatch) : next(action); } return isPromise(action.payload) ? action.payload .then(result => dispatch({ ...action, payload: result })) .catch(error => { dispatch({ ...action, payload: error, error: true }); return Promise.reject(error); }) : next(action); }; }
这样的设计与 Redux-thunk 完全不同,它将 thunk 过程控制在中间件自身中,这样一来,第三方轮子做的事情更多,因此在业务调用时更加简练方便。我们只需要正常编写 action 即可:
dispatch({ type: GET_USER, payload: http.getUser(userId) // payload 为 promise 对象 })
我们对比一下 Redux-thunk,相对于“轮子”控制权较弱,业务方控制权更多的 Redux-thunk,实现上述三行代码,就得不得不需要:
dispatch( function(dispatch, getState) { dispatch({ type: GET_USERE, payload: userId }) http.getUser(id) .then(response => { dispatch({ type: GET_USER_SUCCESS, payload: response }) }) .catch(error => { dispatch({ type: GET_DATA_FAILED, payload: error }) }) } )
当然,Redux-promise 控制权越多,一方面带来了简练,但是另一方面,业务控制权越弱,也丧失了一定的自主性。比如如果想实现乐观更新(Optimistic updates),那就很难做了。具体详见 Issue #7
为了平衡这个矛盾,在 Redux-thunk 和 Redux-promise 这两个极端控制权理念的中间件之间,于是便存在了中间状态的中间件:Redux-promise-middleware,它与 Redux-thunk 类似,掌控粒度也类似,但是在 action 处理上更加温和和渐进,它会在适当的时机 dispatch XXX_PENDING、XXX_FULFILLED 、XXX_REJECTED 三种类型的 action,也就是说这个中间件在掌控更多逻辑的基础上,增加了和外界第三方的通信程度,不再是直接高冷地触发 XXX_FULFILLED 、XXX_REJECTED,请读者仔细体会其中不同。
了解了异步状态中的控制权问题,我们再从 Redux 全局角度进行分析。在内部分享时,我将基于 Redux 封装的状态管理类库共同特性总结为这一页 slide:
以上四点都是相关类库基于 Redux 所进行的简化,其中非常有意思的就是后面三点,它们无一例外地与控制权相关。以 Rematch 为代表,它不再是处理 action 到 reducer 的中间件,而是完全控制了 action creator,reducer 以及联通过程。
具体来看:
业务方不再需要显示申明 action type,它由类库直接函数名直接生成,如果 reducer 命名为 increment,那么 action.type 就是 increment;
同时控制 reducer 和 action creator 合二为一,态管理从未变得如此简单、高效。
我把这样的实践称为控制主义或者极简主义,相比 Redux-actions 这样的状态管理类库,这样的做法更加彻底、完善。具体思想可参考 Shawn McKay 的文章,介绍的比较充分,这里我不再赘述。
Le contrôle est en fin de compte une idée de conception, une confrontation et une collision entre des bibliothèques tierces et la consommation de l'entreprise. Cela n'a rien à voir avec le langage et le framework. Cet article n'utilise React qu'à titre d'exemple. En fait, la lutte pour le contrôle peut être vue partout dans le domaine de la programmation ; analyse respectivement dans l'abstraction de l'interface utilisateur et l'abstraction d'état ; droits de contrôle et codeurs. Étroitement lié, il détermine directement notre expérience de programmation et notre efficacité de développement.
Cependant, dans les premières étapes de la programmation, une excellente conception de contrôle est difficile à réaliser du jour au lendemain. Ce n'est qu'en nous consacrant au développement de première ligne, en comprenant véritablement nos propres besoins commerciaux, en résumant un grand nombre de meilleures pratiques, en nous référant à l'essence de la communauté et en analysant les travaux open source exceptionnels, que je crois que nous grandirons tous.
Recommandations associées :
Comment utiliser React Router4+ redux pour implémenter le contrôle des autorisations de routage
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!