下面就从设计思维的角度来谈谈如何设计出更优雅的React组件。基本原则单一职责单一职责原则就是让一个模块专注于一个功能,也就是让一个模块的职责尽可能少。如果一个模块的功能太多,应该拆分成多个模块,更有利于代码维护。就好像一个人最好专心做一件事,把自己负责的每一件事都做到最好。组件也是如此,要求将组件限制在一个合适的粒度上,可以被复用。如果一个组件的功能过于复杂,代码量就会增加。这时候就需要考虑将其拆分成职责单一的小组件。每个小部件只关心自己的功能,组合起来可以满足复杂的需求。单个组件更易于维护和测试,但不要滥用它。仅在必要时拆分组件。最小化粒度是一个极端,它可能会导致大量的模块。模块的离散化也会使项目难以管理。如何划分边界来拆分组件。如果两个组件之间的关系过于密切而无法在逻辑上定义它们各自的职责,则不应拆分这两个组件。否则,各自职责不明确,边界不分明,会导致逻辑混乱的问题。那么拆分组件的关键就是确定边界,通过抽象的参数通信,让每个组件发挥出自己独特的能力。高内聚/低耦合优质的组件必须满足高内聚和低耦合的原则。高内聚意味着逻辑上密切相关的内容聚合在一起。在jQuery时代,我们把一个功能资源放在js、html、css等目录下。在开发的时候,我们需要在不同的目录下寻找相关的逻辑资源。再比如Redux建议将action、reducer、store拆分到不同的地方,分散一个很简单的功能逻辑。这不满足高内聚的特点。抛开Redux,React的组件思维本身就满足了高内聚的原则,即组件是一个自包含的单元,包含逻辑/样式/结构,甚至依赖的静态资源。低耦合是指降低不同组件之间的依赖关系,让每个组件尽可能独立。也就是说,写代码通常都是为了低耦合而做的。通过分离职责和划定边界来分离复杂的业务。遵循基本原则的好处:降低单个组件的复杂度,可读性高,降低耦合,不影响整体,提高复用性,边界透明,易于测试,流程清晰,降低错误率,便于高级设计调试受控/非受控状态React表单管理中有两个常用的术语:受控输入和非受控输入。简单来说,受控意味着当前组件的状态成为表单的唯一数据源。表示表单的值在当前组件的控制下,只能通过setState更新。受控/不受控的概念在组件设计中很常见。受控组件通常与value和onChange配对。传递给子组件,子组件不能直接修改这个值,只能通过onChange回调告诉父组件更新。非受控组件可以传入defaultValue属性来提供初始值。Modal组件的可见性受控/不受控://controlled//uncontrolled如果这个状态作为组件的核心逻辑,那么它应该支持受控,或者兼容非托管模式。如果状态是二级逻辑,可以根据实际情况选择性支持受控模式。比如Select组件处理受控和非受控逻辑:functionSelect(props:SelectProps){//value和onChange是核心逻辑,支持controlled。兼容传入的defaultValue变成不受控//defaultOpen是次级逻辑,可以不受控const{value:controlledValue,onChange:onControlledChange,defaultValue,defaultOpen}=props;//不受控模式使用内部状态const[innerValue,onInnerValueChange]=React。useState(defaultValue);//二级逻辑,选择框展开状态const[visible,setVisible]=React.useState(defaultOpen);//检查参数是否包含value属性判断是否被控制,虽然value是undefinedconstshouldControlled=Reflect.has(props,'value');//支持受控和非受控处理constvalue=shouldControlled?controlledValue:innerValue;constonChange=shouldControlled?onControlledChange:onInnerValueChange;//...}withhooks组件是否受控通常是自己支持的,现在自定义hooks的出现可以突破这个限制。对于复杂的组件,配合钩子会更得心应手。封装此类组件,将逻辑放在hooks中,组件本身被挖空,其作用主要是配合自定义的hooks进行渲染。functionDemo(){//主要逻辑在自定义hookconstsheet=useSheetTable();//组件本身只接收一个参数,即hook的返回值;}优点这样做是逻辑和组件完全分离,更有利于状态提升,可以直接访问sheet的所有状态。这种模式将受到更彻底的控制。简单的组件可能不适合这种模式,它们没有那么大的控制需求,所以封装会增加使用的复杂度。单一数据源原则单一数据源是指组件的一个状态以props的形式传递给子组件,并且在传递过程中具有连续性。也就是说,state在传递给各个子组件的时候,并没有使用useState来接收,这会让传递过来的state失去响应性。下面的代码违反了单一数据源的原则,因为在子组件中定义了statesearchResult来缓存搜索结果,这会导致options参数在onFilter之后失去对子组件的响应性。functionSelectDropdown({options=[],onFilter}:SelectDropdownProps){//缓存搜索结果const[searchResult,setSearchResult]=React.useState