常熟专业网站建设,网站制作需要什么资料,网站云主机,珠海做网站的网络公司作为一名 React 开发者#xff0c;你可能会面临下面几个问题#xff1a;
如何构建一个高复用度性的组件#xff0c;使其适应不同的业务场景#xff1f;如何构建一个具有简单 API的组件#xff0c;使其易于使用#xff1f;如何构建一个在 UI 和功能方面具有可扩展性的组件…作为一名 React 开发者你可能会面临下面几个问题
如何构建一个高复用度性的组件使其适应不同的业务场景如何构建一个具有简单 API的组件使其易于使用如何构建一个在 UI 和功能方面具有可扩展性的组件
为解决上述问题下面介绍五种 React 组件设计模式并对比它们的优缺点。
1. 复合组件模式
复合组件模式是一种通过将多个简单组件组合在一起创建更复杂组件的方法。这种模式使得组件的逻辑分离每个简单组件负责特定的功能。通过复合组件可以轻松构建可复用的、功能完备的组件。
如果想要设计一个定制化程度高API方便理解的组件可以考虑这个模式这种模式不会出现多层Props传递的情况。
import React, { useState } from react;// 基础按纽组件
const Button ({ label, onClick }) (button onClick{onClick}{label}/button
);// 基础文本组件
const TextBox ({ value, onChange }) (input typetext value{value} onChange{onChange} /
);// 复合组件
const LoginPanel () {const [username, setUsername] useState();const [password, setPassword] useState();const handleLogin () {// 实现登录逻辑console.log(Logging in with ${username} and ${password});};return (div classNamelogin-panelTextBox value{username} onChange{(e) setUsername(e.target.value)} /TextBox value{password} onChange{(e) setPassword(e.target.value)} /Button labelLogin onClick{handleLogin} //div);
};// 使用示例
const App () {return (LoginPanel /);
};export default App;
在这个例子中LoginPanel 是一个复合组件它包含了两个基本组件 TextBox 和一个带有登录逻辑的 Button。
优点
API 复杂度降低 避免将Props全部塞入一个容器组件中而是直接将Props传递给相对应的子组件。高度可复用性 基础组件可以在多个场景中重复使用。逻辑分离 每个基础组件专注于一项任务。组件数量增多 随着组件层级的增加将会增加JSX的行数并且代码可能变得复杂。不适用于所有场景 对于简单的场景引入复合组件模式可能会显得繁琐和不必要。
适用场景
表单和表单域 当设计表单时可以使用复合式组件将整个表单拆分成多个表单域组件每个表单域负责处理特定的输入或验证逻辑。这样可以更好地组织表单逻辑提高可维护性。对话框和模态框 对话框或模态框通常包含标题、内容和操作按钮。可以使用复合式组件将这些部分拆分成独立的组件以便在应用中以不同方式重复使用。
2. 受控组件模式
受控组件模式就是将组件转换为受控组件通过直接修改 Props 影响组件内部的状态一般在表单组件中比较常用。
import React, { useState } from react;const Button ({ label, onClick }) (button onClick{onClick}{label}/button
);const TextBox ({ value, onChange }) (input typetext value{value} onChange{onChange} /
);// 受控组件模式的复合组件
const ControlledLoginPanel () {const [loginData, setLoginData] useState({ username: , password: });const handleInputChange (e) {const { name, value } e.target;setLoginData((prevData) ({...prevData,[name]: value,}));};const handleLogin () {// 实现登录逻辑console.log(Logging in with ${loginData.username} and ${loginData.password});};return (div classNamelogin-panelTextBoxvalue{loginData.username}onChange{handleInputChange}/TextBoxvalue{loginData.password}placeholderPassword/Button labelLogin onClick{handleLogin} //div);
};// 使用示例
const App () {return (ControlledLoginPanel /);
};export default App;
在这个例子中ControlledLoginPanel 组件就是一个受控组件的例子其中的输入框的值由 React 状态管理。
优点
提供更多的控制 将内部的状态暴露在组件之外允许用户通过控制它而直接影响组件。一致性和可预测性 React 组件的状态是单一数据源使得应用的状态变得更加可预测和一致。状态的变化完全由 React 控制减少了意外的行为。 缺点繁琐的代码 受控组件相对于非受控组件来说需要更多的代码。每个输入框都需要设置对应的状态和事件处理函数这可能导致代码量的增加。性能开销 受控组件每次输入变化都会触发状态更新可能导致频繁的重新渲染。对于大型或性能敏感的应用这可能带来一些性能开销。不适用于所有场景受控组件更适用于表单交互比较复杂需要实时验证或涉及多个输入字段之间关系的场景。对于简单的表单可能显得有些繁重。
适用场景
动态表单元素 在需要动态添加或删除表单元素的情况下受控组件模式可以很容易地实现。通过使用数组来保存表单元素的状态可以动态渲染和更新表单。模态框控制 当需要通过 props 控制模态框的显示或隐藏状态时可以使用受控组件模式。
3. 自定义 Hooks 模式
自定义Hooks模式是一种将组件逻辑提取为可重用的函数的方法。将主要的逻辑转移到一个Hooks中。用户可以访问这个Hooks并公开了几个内部逻辑(状态、处理程序) 使用户能够更好地控制组件。
import React, { useState } from react;const Button ({ label, onClick }) (button onClick{onClick}{label}/button
);const TextBox ({ value, onChange, placeholder }) (input typetext value{value} onChange{onChange} placeholder{placeholder} /
);// 自定义 Hook处理登录表单逻辑
const useLoginForm () {const [loginData, setLoginData] useState({ username: , password: });const handleInputChange (e) {const { name, value } e.target;setLoginData((prevData) ({...prevData,[name]: value,}));};const handleLogin () {// 在这里实现登录逻辑console.log(使用用户名 ${loginData.username} 和密码 ${loginData.password} 登录);};return {loginData,handleInputChange,handleLogin,};
};// 在组件中使用自定义 Hook
const ControlledLoginPanel () {const { loginData, handleInputChange, handleLogin } useLoginForm();return (div classNamelogin-panelTextBoxvalue{loginData.username}onChange{handleInputChange}placeholder用户名/TextBoxvalue{loginData.password}onChange{handleInputChange}placeholder密码/Button label登录 onClick{handleLogin} //div);
};// 使用示例
const App () {return (ControlledLoginPanel /);
};export default App;
在这个例子中我们将与登录表单相关的状态和逻辑抽离到一个自定义 useLoginForm Hook 中。使得 ControlledLoginPanel 组件更专注于渲染 UI减少了状态和事件处理逻辑的混杂。
优点
逻辑重用 将逻辑提取为 Hooks可以在多个组件中重用。组件更简洁 组件代码更加清晰只关注与 UI 相关的逻辑。 缺点实现复杂度变高 逻辑部分与渲染部分分开需要将两者结合起来才能很好的理解组件工作原理。 适用场景数据获取和处理逻辑 将数据获取和处理逻辑提取到自定义 Hook 中可以在多个组件之间共享相同的数据逻辑。副作用的封装 当有需要在组件中处理副作用的情况可以将副作用逻辑封装到自定义 Hook 中以提高可维护性。
4. Props Getters 模式
模式 3 中的自定义Hooks提供了很好的控制方式但是比较难以集成使用者需要按照组件提供的Hooks与State相结合进行编写逻辑提高了集成的复杂度。Props Getters模式则是通过简化这一过程来实现。Getter是一个返回多个属性的函数它具有有意义的名称使得开发者能够清楚地知道哪个Getter对应于哪个JSX元素。
import React, { useState } from react;const Button ({ getLabel, handleClick }) (button onClick{handleClick}{getLabel()}/button
);const TextBox ({ getValue, onChange, placeholder }) (input typetext value{getValue()} onChange{onChange} placeholder{placeholder} /
);const ControlledLoginPanel ({ getUsernameProps, getPasswordProps, handleLogin }) {return (div classNamelogin-panelTextBox {...getUsernameProps()} placeholderUsername /TextBox {...getPasswordProps()} placeholderPassword /Button getLabel{() Login} handleClick{handleLogin} //div);
};// 使用 Props Getters 模式的 Hooks
const useLoginForm () {const [loginData, setLoginData] useState({ username: , password: });const handleInputChange (name) (e) {const { value } e.target;setLoginData((prevData) ({...prevData,[name]: value,}));};const handleLogin () {// 实现登录逻辑console.log(Logging in with ${loginData.username} and ${loginData.password});};const getUsernameProps () ({getValue: () loginData.username,onChange: handleInputChange(username),});const getPasswordProps () ({getValue: () loginData.password,onChange: handleInputChange(password),});return {getUsernameProps,getPasswordProps,handleLogin,};
};// 使用示例
const App () {const { getUsernameProps, getPasswordProps, handleLogin } useLoginForm();return (ControlledLoginPanelgetUsernameProps{getUsernameProps}getPasswordProps{getPasswordProps}handleLogin{handleLogin}/);
};export default App;
在这个例子中我们基于模式 3 进行了改造把 ControlledLoginPanel 组件需要的 Props 通过函数的方式进行获取以实现更灵活、更简便的组件复用。
优点
易用性 开发人员只需要将 Getter传入到正确的 JSX元素即可。组件关注点分离 组件通过 props 获取所需的属性使组件关注点更为分离组件本身不处理状态和逻辑提高了组件的可维护性。减少嵌套层级 相较于 Hooks 模式Props Getters 模式可能减少了一些嵌套使得组件结构更加扁平。
缺点
缺乏可见性 Getter 带来了抽象使组件更容易集成但也更为黑盒。引入更多回调函数 使用 Props Getters 模式可能引入更多的回调函数一些开发者可能认为这会使代码显得更加复杂。依赖外部 API Props Getters 模式依赖外部传递的回调函数可能导致一些依赖关系不够自包含。
适用场景
数据过滤 在一个数据展示组件中通过 Props Getters 模式可以将数据过滤逻辑提取出来允许外部根据特定条件获取过滤后的数据。表单验证 在一个表单组件中通过 Props Getters 模式可以将表单验证的逻辑从组件中抽离允许外部调用表单组件的验证函数并获取验证结果。
5. State Reducer 模式
State Reducer 模式是一种通过将组件的状态更新逻辑委托给一个函数实现更灵活的状态管理方式。这种模式通常在处理复杂的状态逻辑时非常有用。
import React, { useState } from react;const TextInput ({ getInputProps }) {const inputProps getInputProps();return input {...inputProps} /;
};const StateReducerExample () {// 初始状态为一个空字符串const [inputValue, setInputValue] useState();// stateReducer 函数用于处理状态的变化const stateReducer (state, changes) {// 使用 switch case 处理不同的状态变化情况switch (Object.keys(changes)[0]) {// 如果变化的是 value 属性case value:// 如果输入的字符数量超过 10 个则不允许变化if (changes.value.length 10) {return state;}break;// 可以添加其他 case 处理不同的状态变化default:break;}// 返回新的状态return { ...state, ...changes };};// 获取传递给子组件的 propsconst getInputProps () {return {value: inputValue,// 在输入框变化时调用 stateReducer 处理状态变化onChange: (e) setInputValue(stateReducer({ value: e.target.value })),};};return (divh3State Reducer Example/h3{/* 将获取的 props 传递给 TextInput 组件 */}TextInput getInputProps{getInputProps} //div);
};export default StateReducerExample;
在这个例子中StateReducerExample 组件包含一个输入框通过 getInputProps 函数将输入框的值和变化处理逻辑传递给 TextInput 组件。stateReducer 函数处理状态的变化确保输入的字符数量不超过 10 个。
优点
状态管理灵活 可以通过自定义的状态更新函数实现更复杂的状态管理逻辑。更好的组织代码 将状态的处理逻辑集中在一个 stateReducer 函数中可以使代码更有组织性减少了在组件中处理状态的复杂性。清晰的状态更新逻辑 通过 stateReducer 可以清晰地看到每个状态变化是如何被处理的使得状态更新逻辑更易于理解。
缺点
增加复杂度 引入 stateReducer 可能会使代码结构变得更加复杂尤其是在处理多个状态变化情况时。这可能导致一些开发者对代码的理解产生困难。可能造成冗余代码 在某些情况下可能会因为需要为每个状态变化情况编写处理逻辑而导致一些冗余的代码特别是在处理简单状态时。不适用于简单场景 在简单场景下使用状态约减可能显得繁琐不必要。
适用场景
复杂状态管理 当组件的状态比较复杂有多个相关联的状态需要进行更新时State Reducer 模式可以帮助将状态管理逻辑进行更细粒度的控制。异步状态更新 当需要进行异步状态更新时State Reducer 模式可以帮助处理异步回调以确保状态正确更新。控制状态更新流程 在某些场景下需要更灵活地控制状态更新的流程例如在某个条件下阻止状态更新或根据条件进行额外的处理。
结论
通过这 5 种 React 组件设计模式我们对“控制度”和“复杂度”有了更清晰的认识下图是复杂度和控制度的一个趋势图。 总体来说设计的组件越灵活功能也就越强大复杂度也会更高。作为开发人员建议大家根据自己的业务逻辑以及使用人群灵活使用以上的设计模式。
参考文章
React 组件设计模式