简体   繁体   English

在 React 中重用组件逻辑

[英]Reuse component logic in React

I have a more general/conceptual question - in React, how does one go about creating a component that can be build upon.我有一个更一般/概念性的问题 - 在 React 中,一个 go 如何创建一个可以构建的组件。 Let me explain:让我解释:

Say we have a <PersonalInfo.jsx/> and in it we have text fields for name , age and address .假设我们有一个<PersonalInfo.jsx/> ,其中我们有nameageaddress的文本字段。 The application can be used both by civilians and by police officers.该应用程序可供平民和警察使用。 If it is used by a police officer we also want to have a field department number between age and address .如果它被警察使用,我们还希望在ageaddress之间有一个现场department number It can also be used by doctors and in that case we need to add a specialization field between name and age .医生也可以使用它,在这种情况下,我们需要在nameage之间添加一个specialization字段。 One way is to have a <PoliceOfficerPersonalInfo.jsx/> and just duplicate everything (ugh.).一种方法是拥有一个<PoliceOfficerPersonalInfo.jsx/>并复制所有内容(呃。)。 Another way is to use a HOC but I can't figure out how to go about it exactly?另一种方法是使用 HOC,但我不知道如何准确了解 go? Any other ideas?还有其他想法吗?

I don't see how a Higher Order Component would/could help solve this issue as a HOC is really only is capable of injecting props and behavior, but they can't go and change the UI, ie the JSX.我看不出高阶组件如何/可以帮助解决这个问题,因为 HOC 实际上只能注入道具和行为,但它们不能 go 并更改 UI,即 JSX。

React is designed with composition in mind, so you should think abstractly about the UI elements that make up what a "PersonalInfo" component is, ie what are the smaller building block components that can be created to compose a larger component. React 在设计时考虑了组合,因此您应该抽象地考虑构成“PersonalInfo”组件的 UI 元素,即可以创建哪些较小的构建块组件来组合较大的组件。 From what you've provided I'm guessing you have a collection of fields/properties that when taken together represent a person's "personal info".根据您提供的内容,我猜您有一组字段/属性,这些字段/属性放在一起代表一个人的“个人信息”。

From here you go one of few directions:从这里你 go 几个方向之一:

  1. Use the smaller building block components to build out different similar components that just happen to share a lot of similar UI elements, ie your PersonalInfo and PoliceOfficerPersonalInfo components.使用较小的构建块组件构建不同的相似组件,这些组件恰好共享许多相似的 UI 元素,即您的PersonalInfoPoliceOfficerPersonalInfo组件。 Pro is each component has a single specific use, but the con is if any field that is common to multiple components needs to be updated you may need to track them all down (mitigated if compositional building blocks designed well).优点是每个组件都有一个特定的用途,但缺点是如果需要更新多个组件共有的任何字段,您可能需要全部跟踪它们(如果组合构建块设计良好,则可以减轻)。
  2. Create a single general purpose "personal info" container that displays a specific set of information, and expose out props to conditionally render extra fields.创建一个通用的“个人信息”容器,用于显示一组特定的信息,并公开道具以有条件地呈现额外的字段。 The pro: one single component, but the con is what I call prop creep where if not properly groomed/maintained can get out of hand and you end up with a monolithic component that does everything (maybe good, maybe not so well).专业人士:一个单一的组件,但缺点就是我所说的道具蠕变,如果没有正确修饰/维护可能会失控,你最终会得到一个可以完成所有事情的整体组件(也许很好,也许不太好)。
  3. Create a wrapper container to control the general layout, but render children via the children prop.创建一个包装容器来控制总体布局,但通过children属性呈现子级。 The pro here is you get the container you want to put the UI in, and you decide at design time what children to display.这里的优点是您获得了要放入 UI 的容器,并在设计时决定要显示哪些子项。 Think of this as a super div, ie <PersonalInfo>{props.children}</PersonalInfo> .将其视为一个超级 div,即<PersonalInfo>{props.children}</PersonalInfo> A con could be that you don't have a pre-fabricated specialized component lying around to just slap in somewhere.一个缺点可能是您没有一个预制的专用组件,只是在某个地方拍打。

There are many approaches that you can use but I would just create component as CommonTextFields and use for repeated part.您可以使用许多方法,但我只会将组件创建为 CommonTextFields 并用于重复部分。 It is more readable and maintable that way even though you have some level of code repeat.即使您有一定程度的代码重复,它也更具可读性和可维护性。

const PageA = () => {
  // do your validation and fetch logic here

  return (
    <>
      <CommonFields age={age} name={name} value={address} />
      <FieldA value={fieldA} />
    </>
  );
};
const PageB = () => {
  // do your validation and fetch logic here

  return (
    <>
      <CommonFields />
      <FieldB />
    </>
  );
};

But if you insist non render parts (validation / fetch logic etc..) to not repeat too (which is i think bad idea as it will kill maintability).但是,如果您坚持非渲染部分(验证/获取逻辑等)也不要重复(我认为这是个坏主意,因为它会破坏可维护性)。 There are HOC and renderProps options;有 HOC 和 renderProps 选项; also you may support this with customHooks.您也可以使用 customHooks 来支持这一点。 But in that case you need to find a way to include to the fetch and validation logic for the parts that are not repeated.但是在这种情况下,您需要找到一种方法来包含不重复部分的获取和验证逻辑。

// Really looks so messy and not scalable
// Yhis is only one field, imagine for array of fields
const CommonFieldsHOC => ( Field, fieldName, validationFunc ) => ( props ) => {

  const [extraField, setExtraField] = useState()
  const commonValidation = () => {}

  // Find a way to include extraFields logic to validation and Fetch
  handleSubmit = () => {
    const isCommonFieldsValid = commonValidation()
    const isFieldValid = validationFunc(extraField)
    if(isFieldValid && isCommonFieldsValid) {
      submitFunction({ name, age, address,
        [fieldName]: extraField
      })
    } else {
      // give some warning
    }
  }

  return (
    <>
      <Name value={name} />
      <Age value={age} />
      <Address value={address} />
      <Field value={extraField} onChange={extraField} />
      <Button onClick={handleSubmit}>
    </>
  )
};

And use it like this:并像这样使用它:

const MyExtraField = () => <MyExtraField />
const validateMyExtraField = (value) => value > 0 

const MyForm = CommonFieldsHOC(MyExtraField, 'MyExtraField', validateMyExtraField )

const Page = () => {
  return <>
    <MyForm />
  </>
}


you can add a Boolean to show or hide a specific information in the component so you can reuse it.您可以添加Boolean以显示或隐藏组件中的特定信息,以便您可以重复使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM