直接传递 JSX 创建好的元素
把要传递的组件作为 JSX 元素写在属性值里,然后在接收的组件里用 {this.props.xxx} 来渲染。这种方法的优点是直观和灵活,缺点是可能造成不必要的重复渲染。
// 父组件
function Profile() {return (<div><Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /><Avatar size={80} person={{ name: 'Aklilu Lemma', imageId: 'OKS67lh' }} /><Avatar size={50} person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} /></div>);
}// 子组件
function Avatar({ person, size }) {return (<imgclassName="avatar"src={getImageUrl(person)}alt={person.name}width={size}height={size}/>);
}
直接传递 JSX 创建好的元素的方法会造成不必要的渲染,是因为每次父组件重新渲染时,都会创建一个新的 JSX 元素,即使它的内容没有变化。这样会导致 React 认为子组件的属性发生了变化,从而触发子组件的重新渲染。
在上述代码中,每次 Profile 重新渲染时,都会创建一个新的 JSX 元素,每次 person 属性变化时,都会重新渲染 Avatar。
传递组件本身
把要传递的组件作为一个变量或常量,然后把它赋值给属性。这种方法的优点是可以避免重复渲染,缺点是需要额外定义一个变量或常量。
// 父组件
import { DownloadOutlined } from '@ant-design/icons';function Profile() {return (<div><Button icon={<DownloadOutlined />} /></div>);
}// 子组件
function Button({ icon }) {return (<button className="button">{icon}</button>);
}
传递返回 JSX 创建好的元素的函数
把要传递的组件封装成一个函数,然后把函数赋值给属性。
// 父组件
function Profile() {return (<div><Button renderIcon={() => <DownloadOutlined />} /></div>);
}// 子组件
function Button({ renderIcon }) {return (<button className="button">{renderIcon()}</button>);
}
这种方法的优点是可以实现动态渲染和传递参数,缺点是可能造成性能损失。是因为每次父组件重新渲染时,都会调用一次函数,即使函数的返回值没有变化。这样会导致 React 认为子组件的属性发生了变化,从而触发子组件的重新渲染。
在上述代码中,每次 Profile 重新渲染时,都会调用一次 renderIcon 函数;每次 renderIcon 属性变化时,都会重新渲染 Button。
为了避免这种情况,可以使用 useCallback 钩子来缓存函数的引用。或者使用 React.memo 来优化子组件的渲染性能。
使用 useCallback 钩子来缓存函数的引用
// 父组件
import React, { useCallback } from 'react';function Profile() {// \uD83D\uDC47️ 使用 useCallback 钩子来缓存函数的引用,避免每次重新渲染时都创建一个新的函数const renderIcon = useCallback(() => <DownloadOutlined />, []);return (<div><Button renderIcon={renderIcon} /></div>);
}// 子组件
function Button({ renderIcon }) {return (<button className="button">{renderIcon()}</button>);
}
使用 React.memo 来优化子组件的渲染性能
// 父组件
function Profile() {return (<div><Button renderIcon={() => <DownloadOutlined />} /></div>);
}// 子组件
// \uD83D\uDC47️ 使用 React.memo 来包裹子组件,避免属性相同的情况下重新渲染
const Button = React.memo(function Button({ renderIcon }) {return (<button className="button">{renderIcon()}</button>);
});