[React] 你不了解但有用的API: React.Children 与 React.cloneElement

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

API 介绍

React.Children

用 React.Children,你可以处理 props.children,主要方法如下:

React.Children.map

React.Children.map(children, function[(thisArg)])
复制代码

在 children 里的每个直接子节点上调用一个函数。如果 children 是一个数组,它将被遍历并为数组中的每个子节点调用该函数。如果子节点为 null 或是 undefined,则此方法将返回 null 或是 undefined,而不会返回数组。

【注意】

如果 children 是一个 Fragment 对象,它将被视为单一子节点的情况处理,而不会被遍历。

cloneElement()

React.cloneElement(
  element,
  [props],
  [...children]
)
复制代码

以 element 元素为样板克隆并返回新的 React 元素。返回元素的 props 是将新的 props 与原始元素的 props 浅层合并后的结果。新的子元素将取代现有的子元素,而来自原始元素的 key 和 ref 将被保留。

React.cloneElement() 几乎等同于:

<element.type {...element.props} {...props}>{children}</element.type>
复制代码

我为什么说是“几乎”呢?有什么差别呢?

差别在于,React.cloneElement()保留了组件的 ref。相同的 ref 将添加到克隆后的新元素中。

举个例子

以下代码,都可以直接复制到codesandbox,查看效果: codesandbox.io/s/fe4n6

栅格Card对齐

栅格布局下,如果每个元素是个Card,内容是后端给的,他们的高度不统一,可能出现参差不齐的情况:

import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Row, Col } from 'antd';

const App = (props) => {
  const a = new Array(props.length).fill('A').join(' ');
  return (
    <div style={{background: 'red'}}>
      {a}
    </div>
  );
};

const data = [20, 30, 40, 50];

ReactDOM.render(
  <>
    <Row gutter={24}>
      {data.map((item, index) => (
        <Col key={index} span={6}>
          <App length={item}/>
        </Col>
      ))}
    </Row>
  </>,
  document.getElementById('container'),
);
复制代码

在这里插入图片描述

解决方案

当然,你可以利用flex,设置Row是flex,并设置align-items: stretch;,并为每个<App />添加样式height: 100%

import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Row, Col } from 'antd';

const App = (props) => {
  const a = new Array(props.length).fill('A').join(' ');
  return (
    <div style={{background: 'red', ...props.style}}>
      {a}
    </div>
  );
};

const data = [20, 30, 40, 50];

ReactDOM.render(
  <>
    <Row gutter={24} style={{ alignItems: 'stretch'}}>
      {data.map((item, index) => (
        <Col key={index} span={6}>
          <App style={{height: '100%'}} length={item}/>
        </Col>
      ))}
    </Row>
  </>,
  document.getElementById('container'),
);

复制代码

在这里插入图片描述

但是这不方便。

最方便的是封装一下Row和Col。并且在Col中直接给children的所有元素赋style值 height: 100%。大大减少了开发者心智负担。(开发组件库时很有用,尤其是基于antd等封装自己的业务组件时)

import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Row, Col } from 'antd';

const MyRow = (props) => {
  return (
    <Row
      {...props}
      style={{ alignItems: 'stretch', ...props.style }}
    />
  );
};

const MyCol = (props) => {
  const { children, ...otherProps } = props;
  return (
    <Col
      {...otherProps}
    >
      {React.Children.map(children, (child) => {
        return React.cloneElement(
          child,
          { style: { ...child.props.style, height: '100%' }}
        );
      })}
    </Col>
  );
};

const App = (props) => {
  const a = new Array(props.length).fill('A').join(' ');
  return (
    <div style={{background: 'red', ...props.style}}>
      {a}
    </div>
  );
};

const data = [20, 30, 40, 50];

ReactDOM.render(
  <>
    <MyRow gutter={24} style={{ alignItems: 'stretch'}}>
      {data.map((item, index) => (
        <MyCol key={index} span={6}>
          <App length={item}/>
        </MyCol>
      ))}
    </MyRow>
  </>,
  document.getElementById('container'),
);
复制代码

解决方案

写在最后

我是HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,联系我,交个朋友),转发本文前需获得作者HullQin授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费无广告。还独立开发了《合成大西瓜重制版》。还开发了《Dice Crush》参加Game Jam 2022。喜欢可以关注我噢~我有空了会分享做游戏的相关技术,会在这2个专栏里分享:《教你做小游戏》《极致用户体验》

猜你喜欢

转载自juejin.im/post/7130277446095470599