Dieser Artikel bietet Ihnen eine Einführung in das erweiterte Design und die Steuerung von React. Freunde in Not können darauf zurückgreifen.
Steuerung – Dieses Konzept ist bei der Programmierung von entscheidender Bedeutung. Beispielsweise ist der „Wettbewerb“ zwischen der Kapselungsschicht „Wheel“ und der Business-Consumer-Schicht um die Kontrolle ein sehr interessantes Thema. Das ist in der React-Welt nicht anders. Oberflächlich betrachtet hoffen wir natürlich, dass das „Rad“ so viele Dinge wie möglich steuern kann: Denn je mehr Logik die Abstraktionsschicht verarbeitet, desto weniger Dinge müssen wir uns beim Aufrufen des Geschäfts kümmern und desto bequemer ist es es ist zu verwenden. Allerdings „trauen sich manche Designs nicht, zu weit zu gehen“. Das Tauziehen zwischen dem „Rad“ und dem Unternehmen um die Kontrolle ist sehr interessant.
Gleichzeitig hängen die Steuerungsmöglichkeiten auch eng mit dem Komponentendesign zusammen: Atomkomponentendesigns wie Atomkomponenten werden hoch geschätzt. Zusätzlich zum Konzept der Atomkomponenten gibt es auch molekulare Komponenten: Molekülkomponenten. Ob Moleküle oder Atome, sie alle haben eine Daseinsberechtigung bei der Lösung geschäftlicher Probleme.
In diesem Artikel wird das React-Framework als Hintergrund verwendet, um über einige meiner Gedanken und Schlussfolgerungen zur Kontrolle während der Entwicklung zu sprechen. Wenn Sie React nicht nutzen, hindert es Sie grundsätzlich trotzdem nicht am Lesen
Bevor ich mit dem Artikel beginne, möchte ich Ihnen ein Buch vorstellen.
Seit letztem Jahr haben Yan Haijing, ein bekannter Technologieexperte, und ich eine gemeinsame Autorenreise begonnen. Dieses Jahr haben wir gemeinsam das Buch „React State Management and Isomorphism in Practice“ verfeinert. wurde endlich offiziell veröffentlicht! Dieses Buch verwendet den React-Technologie-Stack als Kern. Basierend auf der Einführung der React-Nutzung analysiert es Redux-Ideen auf Quellcodeebene und konzentriert sich auch auf die Architekturmuster des serverseitigen Renderings und isomorpher Anwendungen. Das Buch enthält viele Projektbeispiele, die den Benutzern nicht nur die Tür zum React-Technologie-Stack öffnen, sondern auch das allgemeine Verständnis der Leser für aktuelle Bereiche verbessern.
Beginnen Sie mit kontrollierten und unkontrollierten KomponentenWenn wir React zum ersten Mal betreten, kommen wir als erstes mit dem Konzept der Kontrolle in Berührung: kontrollierte Komponenten und unkontrollierte Komponenten. Diese beiden Konzepte werden oft mit Formen in Verbindung gebracht. In den meisten Fällen wird empfohlen, kontrollierte Komponenten wie Formulare und Eingabefelder zur Implementierung der Zustandssteuerung zu verwenden. In kontrollierten Komponenten werden Daten wie Formulare von der React-Komponente selbst verarbeitet. Nicht kontrollierte Komponenten bedeuten, dass die Daten des Formulars vom Dom selbst kontrolliert werden. Das Folgende ist eine typische unkontrollierte Komponente: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 (
Dies ist natürlich ein sehr grundlegendes Konzept. Die Leser werden gebeten, weiterzulesen.
UI-„Rad“ und Kontroll-Requisiten-MusterDie oben vorgestellten Beispiele sind das, was ich „engsinnigekontrollierte und unkontrollierte“ Komponenten nenne. Im Großen und Ganzen denke ich, dass sich eine völlig unkontrollierte Komponente auf eine funktionale Komponente oder zustandslose Komponente bezieht, die keine internen Zustände enthält und nur Requisiten akzeptiert . Sein Rendering-Verhalten wird vollständig durch externe Requisiten gesteuert und verfügt über keine eigene „Autonomie“. Solche Komponenten erreichen eine gute Wiederverwendbarkeit und sind gut testbar.
Aber im UI-„Rad“-Design sind„halbautonome“ oder „nicht vollständig kontrollierte“ Komponenten manchmal die bessere Wahl. Wir nennen dies das „Kontroll-Requisiten“-Muster. Um es einfach auszudrücken: Wenn keine relevanten Requisiten übergeben werden, wird ihr eigener Status verwendet, um die Rendering- und Interaktionslogik abzuschließen, wenn relevante Requisiten übergeben werden. Es wird ein Kontrollrecht übergeben, das sein Verhalten auf der Ebene des Geschäftsverbrauchs steuert.
Nachdem ich eine große Anzahl von Community-UI-„Rädern“ recherchiert habe, habe ich herausgefunden, dass Downshift, eine von Kent C. Dodds geschriebene und von PayPal verwendete Komponentenbibliothek, dieses Muster weitgehend übernimmt. Verwenden Sie einfach eine Toogle-Komponente als Beispiel. Wenn diese Komponente von der Geschäftsseite aufgerufen wird: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> ) } }
Wir können die Statusumschaltung der Toggle-Komponente über das Eingabefeld steuern (geben Sie „Ein“ ein, um den Status zu aktivieren, geben Sie „Aus“ ein, um den Status auszublenden), und das können wir auch Klicken Sie auch mit der Maus, um zu wechseln. Zu diesem Zeitpunkt ändert sich auch der Inhalt des Eingabefelds entsprechend. Bitte denken Sie darüber nach: Der Zustand der UI-Komponente Toggle kann vom Geschäftsanrufer gesteuert werden, was den Verbrauch auf Nutzungsebene erleichtert. Im Geschäftscode kann der Status unabhängig davon, ob es sich um eine Eingabe oder eine andere Komponente handelt, gesteuert werden, und wir haben beim Aufruf die vollständige Kontrolle. Gleichzeitig kann die Komponente weiterhin normal funktionieren, wenn Sie beim Aufruf der Toggle-Komponente den props-Wert nicht übergeben. Wie folgt:
<toggle> {({on, getTogglerProps}) => ( <p> <button>Toggle me</button> </p> <p>{on ? 'Toggled On' : 'Toggled Off'}</p> )} </toggle>
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 的文章,介绍的比较充分,这里我不再赘述。
Kontrolle ist letztendlich eine Designidee, eine Konfrontation und Kollision zwischen Bibliotheken von Drittanbietern und dem Geschäftsverbrauch. Es hat nichts mit Sprache und Framework zu tun. Tatsächlich ist der Kampf um Kontrolle überall im Programmierbereich zu sehen Analyse in UI-Abstraktion bzw. Zustandsabstraktion; Kontrollrechte und Codierer eng miteinander verbunden, bestimmt es direkt unsere Programmiererfahrung und Entwicklungseffizienz.
Allerdings ist es in den frühen Phasen der Programmierung schwierig, über Nacht ein hervorragendes Steuerungsdesign zu erreichen. Nur wenn wir uns der Entwicklung an vorderster Front widmen, unsere eigenen Geschäftsanforderungen wirklich verstehen, eine große Anzahl von Best Practices zusammenfassen, uns auf das Wesentliche der Community beziehen und herausragende Open-Source-Werke analysieren, werden wir meiner Meinung nach alle wachsen.
Verwandte Empfehlungen:
So verwenden Sie React Router4+ Redux zur Implementierung der Routing-Berechtigungskontrolle
Das obige ist der detaillierte Inhalt vonEinführung in das erweiterte Design und die Steuerung von React. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!