整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

react native使用ant design表单相互嵌套的问题

React Native中使用Ant Design的Form组件进行表单提交时,如果在一个Form表单内嵌套了另一个Form表单,并且这两个表单位于父子组件之间,并且第二个嵌套的表单有一个提交按钮,而外层表单也有一个提交按钮,可能会遇到警告提示Warning: Instance created by 'useForm' is not connected to any Form element. Forget to pass 'form' prop?。这是因为内部表单的form实例没有正确连接到Form元素。

为了解决这个问题,你需要将外部Form表单的form实例传递给内部Form表单,并且在内部表单的提交按钮上使用form.submit来触发提交操作。

以下是一个示例代码,演示如何在React Native中解决嵌套Form表单警告的问题:

import React from 'react';
import { View, Button } from 'react-native';
import { Form, Input } from 'antd';

const OuterForm = () => {
  const [form] = Form.useForm();

  const onFinish = (values) => {
    console.log('Outer Form:', values);
  };

  return (
    <View>
      <Form form={form} onFinish={onFinish}>
        <Form.Item name="outerField">
          <Input placeholder="Outer Field" />
        </Form.Item>

        <InnerForm form={form} />

        <Form.Item>
          <Button title="Outer Submit" onPress={form.submit} />
        </Form.Item>
      </Form>
    </View>
  );
};

const InnerForm = ({ form }) => {
  const [innerForm] = Form.useForm();

  const onFinish = (values) => {
    console.log('Inner Form:', values);
  };

  return (
    <Form form={innerForm} onFinish={onFinish}>
      <Form.Item name="innerField">
        <Input placeholder="Inner Field" />
      </Form.Item>

      <Form.Item>
        <Button title="Inner Submit" onPress={innerForm.submit} />
      </Form.Item>
    </Form>
  );
};

export default OuterForm;

在上述代码中,我们创建了一个外部Form表单OuterForm,并在其中创建了一个form实例。然后,我们使用form属性将该form实例传递给内部的Form表单InnerForm。

在内部表单InnerForm中,我们同样创建了一个form实例innerForm。然后,我们使用innerForm实例创建了相应的Form组件,并使用该实例来触发内部表单的提交操作。

最后,我们在外部表单的提交按钮上使用form.submit来触发外部表单的提交操作。

通过这样的方式,内部表单将与外部表单关联起来,并且可以正常使用,同时也解决了警告的问题。

请注意,在内部表单中,我们创建了一个独立的innerForm实例。这样可以保持内部表单与外部表单的独立性,避免相互干扰。

生 CSS 嵌套(Native CSS nesting)已经被所有现代桌面浏览器所支持!,但是请注意,移动端浏览器支持的还很有限。

1.原生 CSS 嵌套

原生 CSS 嵌套可以像 SASS、LESS 预处理器一样,将相关的选择器组合在一起,从而减少需要编写的规则数量,它可以节省打字时间,并使语法更易于阅读和维护。您可以将选择器嵌套到任意深度,但要小心不要超过两层或三层。嵌套深度没有技术限制,但它会使代码更难以阅读,并且生成的 CSS 可能会变得不必要的冗长。

.button {
   background-color: red;

   &.warning {
     background-color: blue;
   }

   & .icon {
      width: 1rem;
      height: 1rem;
   }
}

虽然原生 CSS 嵌套语法在过去几年中不断发展,使大多数 Web 开发人员感到满意,但不要指望所有 SCSS 代码都能像您期望的那样直接工作。

2.原生 CSS 嵌套规则

您可以将任何选择器嵌套在另一个选择器中,但它必须以符号开头,例如 &, .(类选择器)、#(ID选择器)、@(对于媒体查询)、:::+~>[。换句话说,它不能是对 HTML 元素的直接引用。下面的代码是无效的,不会对 input 元素选择器进行解析:

.parent {
  color: red;

  input {
    margin: 1em;
  }
}
/* Invalid, because "input" is an identifier. */

解决此问题的最简单方法是使用与号 ( &),它以与 Sass 相同的方式引用当前选择器。

2.1.& 符号的使用

.parent {
  color: red;

  & input {
    margin: 1em;
  }

  /* use pseudo-elements and pseudo-classes */
  &::after {}

  &:hover {}

  &:target {}
}
/* valid, no longer starts with an identifier */

或者,您可以使用其中之一:

  • > input:只对子元素生效
  • :is(input): 将选择器列表作为参数,并选择该列表中任意一个选择器可以选择的元素
  • :where(input):优先级总是为 0

它们都可以在这个简单的示例中工作,但是稍后您可能会遇到更复杂的样式表的特异性问题。

它还&允许您在父选择器上定位伪元素和伪类。例如:

p.my-element {

  &::after {}

  &:hover {}

  &:target {}
}

请注意,& 可以在选择器中的任何位置使用。例如:

.child1 {
  .parent3 & {
    color: red;
  }
}

这将转换为以下非嵌套语法:

.parent3 .child1 { color: red; }

您甚至可以在选择器中使用多个 & 符号:

ul {
  & li & {
    color: blue;
  }
}

这将以嵌套 <ul> 元素 ( ul li ul) 为目标,但如果您想保持理智,我建议不要使用它!

2.2.@ 符号的使用

嵌套媒体查询示例:

p {
  color: cyan;
  @media (min-width: 800px) {
    color: purple;
  }
}

3.原生 CSS 嵌套陷阱

3.1.场景一:父选择器包装在 :is() 中

原生 CSS 嵌套将父选择器包装在 :is() 中,这可能会导致与 Sass 输出的差异,比如以下嵌套代码:

.parent1, #parent2 {
  .child1 {

  }
}

当它在浏览器中解析时,它实际上变成以下内容:

:is(.parent1, #parent2) .child1 {

}

Sass 将相同的代码编译为:

.parent1 .child1,
#parent2 .child1 {

}

3.2.场景二:& 符号后置

您可能还会遇到一个更微妙的问题。考虑一下:

.parent .child {
  .grandparent & {}
}

原生 CSS 等效项是:

.grandparent :is(.parent .child) {}

这与以下错误排序的 HTML 元素匹配:

<div class="parent">
  <div class="grandparent">
    <div class="child">MATCH</div>
  </div>
</div>

MATCH变得有样式是因为 CSS 解析器执行以下操作:

它会查找所有元素,其所属类的child祖先也parent为DOM 层次结构中的任何点。

找到包含MATCH的元素后,解析器会grandparent在 DOM 层次结构中的任何位置再次检查它是否具有 — 的祖先。它找到一个并相应地设置该元素的样式。

Sass 中的情况并非如此,它编译为:

.grandparent .parent .child {} 上面的 HTML 没有样式化,因为元素类不遵循严格的grandparent、parent、 和child顺序。

3.3.场景三:字符串替换

Sass 使用字符串替换,因此如下所示的声明是有效的,并且与类的任何元素相匹配 .btn-primary

.btn {
  &-primary {
    color: blue;
  }
}

但是原生 CSS 嵌套会忽略&-space选择器。

4.CSS 预处理器还需要吗?

从短期来看,现有的 CSS 预处理器仍然至关重要。Sass 开发团队宣布,他们将支持 .css 文件中的原生 CSS 嵌套,并按原样输出代码。他们将一如既往地编译嵌套 SCSS 代码,以避免破坏现有代码库,但当全球浏览器支持率达到 98% 时,他们将开始输出 :is() 选择器。

我猜想,PostCSS 插件等预处理器目前会扩展嵌套代码,但随着浏览器支持的普及,就会取消这一功能。当然,使用预处理器还有其他很好的理由,比如将部分代码捆绑到一个文件中,以及对代码进行精简。但如果嵌套是你唯一需要的功能,你当然可以考虑在较小的项目中使用原生 CSS。

总结

CSS 嵌套是最有用、最实用的预处理器功能之一。浏览器供应商努力创造了一个与 CSS 非常相似的原生 CSS 版本,以满足网络开发人员的需求。虽然两者之间存在细微差别,而且在使用(过于)复杂的选择器时可能会遇到不寻常的特殊性问题,但很少有代码库需要进行彻底修改。

原生嵌套可能会让你重新考虑是否需要 CSS 预处理器,但它们仍能提供其他好处。Sass 和类似工具仍然是大多数开发者工具包的重要组成部分。

React Native 中,如果嵌套的组件重复渲染导致内存泄漏问题,可以采取以下解决方案:

1.使用 React.memo 或 PureComponent:将嵌套组件包裹在 React.memo 或继承自 PureComponent 的组件中。这样可以确保只有在组件的 props 发生变化时才会重新渲染,避免不必要的重复渲染。

const NestedComponent = React.memo((props) => {
  // 组件的渲染逻辑
});

// 或

class NestedComponent extends React.PureComponent {
  render() {
    // 组件的渲染逻辑
  }
}

2.使用 useCallback 或 useMemo:在父组件中,使用 useCallback 和 useMemo 来缓存函数和计算结果。这样可以确保在每次渲染时,相同的函数和计算结果都被重用,避免不必要的重复渲染。

const ParentComponent = () => {
  const memoizedCallback = useCallback(() => {
    // 回调函数的逻辑
  }, []);

  const memoizedValue = useMemo(() => {
    // 计算结果的逻辑
    return result;
  }, []);

  return (
    <NestedComponent callback={memoizedCallback} value={memoizedValue} />
  );
};

3.使用 key 属性:在父组件中,给嵌套组件设置一个唯一的 key 属性。这样可以确保当父组件重新渲染时,React 会重新创建嵌套组件,而不是重复使用之前的实例。使用 key 属性:在父组件中,给嵌套组件设置一个唯一的 key 属性。这样可以确保当父组件重新渲染时,React 会重新创建嵌套组件,而不是重复使用之前的实例。

const ParentComponent = () => {
  const [toggle, setToggle] = useState(false);

  const handleToggle = () => {
    setToggle(!toggle);
  };

  return (
    <View>
      {toggle ? (
        <NestedComponent key="componentA" />
      ) : (
        <NestedComponent key="componentB" />
      )}
      <Button onPress={handleToggle} title="Toggle" />
    </View>
  );
};

通过设置不同的 key 属性,确保在父组件重新渲染时,React 会创建一个新的嵌套组件实例,从而避免重复渲染。

这些方法可以帮助你解决 React Native 中嵌套组件重复渲染导致的内存泄漏问题。选择适合你的情况的方法,并根据需要组合使用。同时,检查代码中是否存在其他可能导致重复渲染的问题,例如不必要的重新创建函数、过度使用内联函数等。