Когда любой проект развивается до определенной сложности, он неизбежно сталкивается с проблемой повторного использования логики. существуетReact
Обычно существуют следующие способы реализации логического мультиплексирования:Mixin
,高阶组件(HOC)
,修饰器(decorator)
,Render Props
,Hook
. В этой статье в основном анализируются преимущества и недостатки вышеуказанных методов, чтобы помочь разработчикам сделать методы более подходящими для бизнес-сценариев.
Mixin
Может быть, это просто отVue
переменаReact
Первый способ, который могут придумать разработчики.Mixin
Он широко используется в различных объектно-ориентированных языках,Его роль заключается в создании эффекта, аналогичного множественному наследованию для языков с одинарным наследованием.. Хотя сейчасReact
был заброшен, ноMixin
действительно былReact
Шаблон проектирования для реализации совместного использования кода.
Обобщенный метод примеси заключается в монтировании методов объекта примеси к исходному объекту путем присваивания для реализации смешивания объектов, подобно функции Object.assign() в ES6. Принцип заключается в следующем:
const mixin = function (obj, mixins) {
const newObj = obj
newObj.prototype = Object.create(obj.prototype)
for (let prop in mixins) {
// 遍历mixins的属性
if (mixins.hasOwnPrototype(prop)) {
// 判断是否为mixin的自身属性
newObj.prototype[prop] = mixins[prop]; // 赋值
}
}
return newObj
};
Использование миксинов в React
Предположим, в нашем проекте нескольким компонентам необходимо установить значение по умолчанию.name
свойства, использованиеmixin
Это может избавить нас от необходимости писать несколько одинаковых компонентов в разных компонентах.getDefaultProps
метод, мы можем определитьmixin
:
const DefaultNameMixin = {
getDefaultProps: function () {
return {
name: "Joy"
}
}
}
чтобы использоватьmixin
, который необходимо добавить в компонентmixins
свойства, а затем пишемmixin
оберните его в массив, используйте его какmixins
Стоимость свойства:
const ComponentOne = React.createClass({
mixins: [DefaultNameMixin]
render: function () {
return <h2>Hello {this.props.name}</h2>
}
})
написаноmixin
Может быть повторно использован в других компонентах.
из-заmixins
Значение свойства представляет собой массив, то есть мыВ одном компоненте можно сделать несколько вызововmixin
. Небольшое изменение в приведенном выше примере дает:
const DefaultFriendMixin = {
getDefaultProps: function () {
return {
friend: "Yummy"
}
}
}
const ComponentOne = React.createClass({
mixins: [DefaultNameMixin, DefaultFriendMixin]
render: function () {
return (
<div>
<h2>Hello {this.props.name}</h2>
<h2>This is my friend {this.props.friend}</h2>
</div>
)
}
})
мы можем дажеmixin
содержит другиеmixin
.
например написать новыйmixin``DefaultProps
в том числе вышеDefaultNameMixin
а такжеDefaultFriendMixin
:
const DefaultPropsMixin = {
mixins: [DefaultNameMixin, DefaultFriendMixin]
}
const ComponentOne = React.createClass({
mixins: [DefaultPropsMixin]
render: function () {
return (
<div>
<h2>Hello {this.props.name}</h2>
<h2>This is my friend {this.props.friend}</h2>
</div>
)
}
})
Пока что мы можем сделать вывод, чтоmixin
Как минимум иметь следующие преимущества:
-
Вы можете использовать одно и то же в нескольких компонентах
mixin
; -
Можно использовать несколько в одном компоненте
mixin
; -
может быть в том же
mixin
несколько вложенныхmixin
;
Но в разных сценариях преимущества могут также превратиться в недостатки:
-
Уничтожьте пакет исходного компонента, возможно, потребуется сохранить новый
state
а такжеprops
состояние ожидания; -
разные
mixin
Именование является агностическим и очень склонным к конфликту; - Может вызывать проблемы с рекурсивными вызовами, увеличивая сложность проекта и сложность обслуживания.;
Помимо,mixin
Он имеет собственную логику обработки для таких проблем, как конфликты состояний, конфликты методов и последовательность вызовов нескольких методов жизненного цикла. Заинтересованные студенты могут обратиться к следующим статьям:
компоненты более высокого порядка
из-заmixin
Вышеупомянутые дефекты существуют, поэтомуReact
раздетыйmixin
, используйте вместо高阶组件
заменить его.
高阶组件
По сути, это функция, которая принимает компонент в качестве параметра и возвращает новый компонент..
React
Чиновники также используют его при реализации некоторых публичных компонентов.高阶组件
,Напримерreact-router
серединаwithRouter
,так же какRedux
серединаconnect
. здесь сwithRouter
Например.
По умолчанию он должен бытьRoute
Существуют только компоненты, маршруты которых соответствуют рендерингу.this.props
, иметь только路由参数
, использовать函数式导航
выполнение письмаthis.props.history.push('/next')
Перейти на страницу соответствующего маршрута.高阶组件
серединаwithRouter
Эффект заключается в преобразованииRoute
Направьте обернутый компонент, обернув егоRoute
внутрь, чтобыreact-router
три объектаhistory
,location
,match
в компонентprops
свойства, так что это может быть достигнуто函数式导航跳转
.
withRouter
Принцип реализации:
const withRouter = (Component) => {
const displayName = `withRouter(${Component.displayName || Component.name})`
const C = props => {
const { wrappedComponentRef, ...remainingProps } = props
return (
<RouterContext.Consumer>
{context => {
invariant(
context,
`You should not use <${displayName} /> outside a <Router>`
);
return (
<Component
{...remainingProps}
{...context}
ref={wrappedComponentRef}
/>
)
}}
</RouterContext.Consumer>
)
}
Используйте код:
import React, { Component } from "react"
import { withRouter } from "react-router"
class TopHeader extends Component {
render() {
return (
<div>
导航栏
{/* 点击跳转login */}
<button onClick={this.exit}>退出</button>
</div>
)
}
exit = () => {
// 经过withRouter高阶函数包裹,就可以使用this.props进行跳转操作
this.props.history.push("/login")
}
}
// 使用withRouter包裹组件,返回history,location等
export default withRouter(TopHeader)
из-за高阶组件
Суть в том获取组件并且返回新组件的方法
, поэтому теоретически это также может быть похоже наmixin
Та же реализация множественной вложенности.
Например:
Напишите функцию высшего порядка, которая позволяет петь
import React, { Component } from 'react'
const widthSinging = WrappedComponent => {
return class HOC extends Component {
constructor () {
super(...arguments)
this.singing = this.singing.bind(this)
}
singing = () => {
console.log('i am singing!')
}
render() {
return <WrappedComponent />
}
}
}
Напишите функцию высшего порядка, которая позволяет танцевать
import React, { Component } from 'react'
const widthDancing = WrappedComponent => {
return class HOC extends Component {
constructor () {
super(...arguments)
this.dancing = this.dancing.bind(this)
}
dancing = () => {
console.log('i am dancing!')
}
render() {
return <WrappedComponent />
}
}
}
Используйте вышеуказанные компоненты более высокого порядка
import React, { Component } from "react"
import { widthSing, widthDancing } from "hocs"
class Joy extends Component {
render() {
return <div>Joy</div>
}
}
// 给Joy赋能唱歌和跳舞的特长
export default widthSinging(withDancing(Joy))
Из вышеизложенного видно, что просто используя функции высокого порядка для простой упаковки, оригинальную Джой можно превратить в маленького принца ночного клуба, который может и петь, и танцевать!
Конвенции для использования HOC
В использованииHOC
В то время существуют некоторые жесткие соглашения:
- Передайте несвязанные реквизиты компоненту-оболочке (передайте реквизиты, не связанные с их конкретным содержимым);
- Пошаговая композиция (избегая объединения разных форм вызовов HOC);
- Включите отображаемое отображаемое имя для облегчения отладки (каждый HOC должен соответствовать обычному отображаемому имени);
- Уходите
render
Используйте компоненты более высокого порядка в функции (каждый рендеринг более высокого порядка возвращает новый компонент, который влияет на производительность diff); - Статические методы должны быть скопированы (новый компонент, возвращаемый более высоким порядком, не содержит статических методов исходного компонента);
- Избегайте использования ref (ref не будет передан);
Преимущества и недостатки ХОС
Пока что мы можем подвести итог高阶组件(HOC)
Преимущества:
-
HOC
это чистая функция, простая в использовании и обслуживании; - также из-за
HOC
Это чистая функция, которая поддерживает передачу нескольких параметров для расширения области применения; -
HOC
То, что возвращается, является компонентом, который можно комбинировать и вкладывать, и он обладает высокой гибкостью;
КонечноHOC
Есть и некоторые проблемы:
- когда несколько
HOC
При вложенности невозможно напрямую судить о подкомпоненте.props
из которогоHOC
ответственный за доставку; - Когда родительский и дочерний компоненты имеют одинаковое имя
props
, приведет к тому, что родительский компонент переопределит дочерний компонент с тем же именемprops
проблема, иreact
Об ошибках не сообщается, а восприятие разработчика низкое; - Каждый
HOC
Все возвращают новый компонент, что приводит к большому количеству бесполезных компонентов и в то же время углубляет иерархию компонентов, что затрудняет устранение неполадок;
修饰器
а также高阶组件
Он относится к той же модели и здесь обсуждаться не будет.
Render Props
Render Props
Это очень гибкий и повторно используемый шаблон, который может инкапсулировать определенное поведение или функцию в компонент и предоставлять его другим компонентам, чтобы позволить другим компонентам иметь такие возможности..
Термин «реквизит рендеринга» относится к методу совместного использования кода между компонентами React с использованием реквизита, значением которого является функция.
ЭтоReact
официальный дляRender Props
Определение , переведенное на местный язык, звучит так: «Render Props
реализуетсяReact Components
Техника совместного использования кода между компонентами,props
содержитfunction
Свойство типа, которое может вызывать компонентprops
свойства для реализации внутренней логики рендеринга компонента».
Официальный пример:
<DataProvider render={(data) => <h1>Hello {data.target}</h1>} />
Как указано выше,DataProvider
Компонент имеетrender
(можно называть другими именами)props
свойство, свойство является функцией, и эта функция возвращаетReact Element
, вызывая эту функцию внутри компонента для завершения рендеринга, то этот компонент используетсяrender props
Технология.
Читатель может задаться вопросом: «Зачем нам нужно вызыватьprops
свойств для достижения внутреннего рендеринга компонента без рендеринга непосредственно в компоненте"?React
официальный ответ,render props
не каждыйReact
Навыки, которыми должны овладеть разработчики, и даже вы, возможно, никогда не воспользуетесь этим методом, но его существование дает разработчикам еще один выбор, когда они думают о совместном использовании кода компонентов.
Render Props
сцены, которые будут использоваться
Нам может понадобиться часто использовать всплывающие окна при разработке проекта. Пользовательский интерфейс всплывающих окон может постоянно меняться, но функции схожи, а именно打开
а также关闭
. кantd
Например:
import { Modal, Button } from "antd"
class App extends React.Component {
state = { visible: false }
// 控制弹窗显示隐藏
toggleModal = (visible) => {
this.setState({ visible })
};
handleOk = (e) => {
// 做点什么
this.setState({ visible: false })
}
render() {
const { visible } = this.state
return (
<div>
<Button onClick={this.toggleModal.bind(this, true)}>Open</Button>
<Modal
title="Basic Modal"
visible={visible}
onOk={this.handleOk}
onCancel={this.toggleModal.bind(this, false)}
>
<p>Some contents...</p>
</Modal>
</div>
)
}
}
Выше самое простоеModel
Используя пример, даже если это простое использование, нам все равно нужно обратить внимание на его состояние отображения и реализовать его метод переключения. Но на самом деле разработчики хотят сосредоточиться только на бизнес-логике, связанной сonOk
, идеальное использование должно быть таким:
<MyModal>
<Button>Open</Button>
<Modal title="Basic Modal" onOk={this.handleOk}>
<p>Some contents...</p>
</Modal>
</MyModal>
в состоянии пройтиrender props
Для достижения вышеуказанного использования:
import { Modal, Button } from "antd"
class MyModal extends React.Component {
state = { on: false }
toggle = () => {
this.setState({
on: !this.state.on
})
}
renderButton = (props) => <Button {...props} onClick={this.toggle} />
renderModal = ({ onOK, ...rest }) => (
<Modal
{...rest}
visible={this.state.on}
onOk={() => {
onOK && onOK()
this.toggle()
}}
onCancel={this.toggle}
/>
)
render() {
return this.props.children({
Button: this.renderButton,
Modal: this.renderModal
})
}
}
Таким образом, мы завершили состояние и основную функциюModal
, мы используем это на других страницахModal
, вам нужно только сосредоточиться на конкретной бизнес-логике.
Как видно из вышеизложенного,render props
настоящийReact
компонент вместо чего-то вродеHOC
такой же только одинФункция, которая может возвращать компонент, что также означает использованиеrender props
не какHOC
Та же проблема вложенности на уровне компонентов, не беспокойтесь об этомprops
Устранение проблем, возникающих из-за конфликтов имен.
render props
ограничения на использование
существуетrender props
следует избегать в箭头函数
, так как это влияет на производительность.
Например:
// 不好的示例
class MouseTracker extends React.Component {
render() {
return (
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
)
}
}
Плохо так писать, потому чтоrender
метод можно отображать несколько раз, используйте箭头函数
, из-за чего каждый раз при рендеринге будет передаватьсяrender
Значение будет отличаться, когда на самом деле нет никакой разницы, что может привести к вопросам производительности.
Так что лучший способ написать это было бы передатьrender
Функции в определены как методы экземпляра, так что даже если мы визуализируем несколько раз, привязка всегда будет одной и той же функцией.
// 好的示例
class MouseTracker extends React.Component {
renderCat(mouse) {
return <Cat mouse={mouse} />
}
render() {
return (
<Mouse render={this.renderTheCat} />
)
}
}
render props
Преимущества и недостатки
-
преимущество
- Имя реквизита можно изменить, взаимного переопределения нет;
- понятный источник реквизита;
- Не будет многоуровневой вложенности компонентов;
-
недостаток
-
сложно писать;
-
невозможно
return
доступ к данным вне оператора; -
Легко сгенерировать вложенность обратного вызова функции;
Следующий код:
const MyComponent = () => { return ( <Mouse> {({ x, y }) => ( <Page> {({ x: pageX, y: pageY }) => ( <Connection> {({ api }) => { // yikes }} </Connection> )} </Page> )} </Mouse> ) }
-
Hook
React
Ядром является составляющая, следовательно,React
Всегда работайте над оптимизацией и совершенствованием способа объявления компонентов. с самого раннего类组件
, затем к函数组件
, у каждого есть преимущества и недостатки.类组件
Он может предоставить нам полный жизненный цикл и состояние (состояние), но очень громоздок в написании, и函数组件
Несмотря на то, что он очень краткий и легкий, его ограниченияДолжна быть чистой функцией, не может содержать состояние и не поддерживает жизненные циклы.,следовательно类组件
не заменяет函数组件
.
а такжеReact
команда чувствуетКомпоненты лучше всего писать как функции, а не классы, в результате чегоReact Hooks
.
Целью разработки React Hooks является улучшение функциональных компонентов, и вы можете написать полнофункциональный компонент, вообще не используя «классы»..
зачем говорить类组件
«Громоздкий», чтобы позаимствоватьReact
Официальный пример гласит:
import React, { Component } from "react"
export default class Button extends Component {
constructor() {
super()
this.state = { buttonText: "Click me, please" }
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState(() => {
return { buttonText: "Thanks, been clicked!" }
})
}
render() {
const { buttonText } = this.state
return <button onClick={this.handleClick}>{buttonText}</button>
}
}
Выше показан простой компонент кнопки, включая самое основное состояние и метод щелчка.После нажатия кнопки состояние изменяется.
Это очень простой функциональный компонент, но для его реализации требуется много кода. из-за函数组件
не содержит состояния, поэтому мы не можем использовать函数组件
объявить компонент с вышеуказанными функциями. Но мы можем использоватьHook
реализовать:
import React, { useState } from "react"
export default function Button() {
const [buttonText, setButtonText] = useState("Click me, please")
function handleClick() {
return setButtonText("Thanks, been clicked!")
}
return <button onClick={handleClick}>{buttonText}</button>
}
В сравнении,Hook
Кажется светлее в непосредственной близости函数组件
При этом он сохраняет собственное состояние.
Первый хук представлен в приведенном выше примере.useState()
,Помимо,React
Чиновник также предоставилuseEffect()
,useContext()
,useReducer()
Подождите крючок. Конкретные хуки и подробности их использования см.официальный.
Hook
Гибкость также ложь, в дополнение к официальным базовым крючкам, мы также можем использовать эту базу пакета и пользовательский крюк к крючкому, что обеспечивает более простое повторное использование кода.
КРЮК выступает
- преимущество
- Легче повторно использовать код;
- Чистый стиль кода;
- меньше кода;
- недостаток
- Асинхронное состояние (функции выполняются независимо, каждая функция имеет отдельную область видимости)
- нужно более рациональное использование
useEffect
- Степень детализации мала, и необходимо абстрагироваться от многих сложных логических элементов.
hook
Суммировать
КромеMixin
Помимо того, что он немного отстает из-за собственных очевидных недостатков, для高阶组件
,render props
,react hook
, это никак нельзя назвать最佳方案
, все они имеют преимущества и недостатки. даже самый популярныйreact hook
, хотя каждыйhook
Это выглядит таким коротким и освежающим, но в реальном бизнесе обычно одна бизнес-функция соответствует несколькимhook
, а это значит, что при изменении бизнеса необходимо поддерживать несколькоhook
изменения, а не сохранениеclass
Другими словами, умственная нагрузка может сильно увеличиться. Только так, как подходит вашему бизнесу最佳方案
.
Справочная документация: