首页 > 解决方案 > 在 React 函数式组件中声明静态变量的最佳方式是什么?

问题描述

在 React 功能组件中声明变量的最佳方式是什么(从现在开始 - RFC)?这与类似的问题不重复。

至于我,有几种声明变量的方法`

  1. 在 RFC中声明它const- 如果我们将它传递给HeavyComponent组件,那么在每次渲染时,它都会创建一个新的引用,并且HeavyComponent也会渲染。不是一个好的选择。
  2. 使用内部 RFC 声明useRef- 在随后的渲染中引用将是相同的,这很好,但另一方面,我们使用的是useRef内部方法(函数调用 - 它在引擎盖下做了一些工作)
  3. 在 RFC(外部范围)之外声明const- 在这种情况下,引用将再次相同,因为它将取自闭包并且我们不使用useRef方法。但是,在这种特殊情况下,我们在外部范围内声明该变量并且它不会被垃圾收集并且会导致内存泄漏(如果我们经常使用这种情况)。

我知道,每种情况都有其优点和缺点。但是我们什么时候坚持使用某个选项呢?

更新 这里是例子

export const UnemployedEmployeesReportPaper = React.memo((props: IProps) => {
    const [filterText, setFilterText] = useState('');
    const [tableData, setTableData] = useState([]);

    const headerColumns = useRef([
        { children: 'First Name', width: 240, flexGrow: 1, sortValue: item => item.FirstName },
        { children: 'Last Name', width: 240, flexGrow: 1, sortValue: item => item.LastName },
        { children: 'Last day of employment', width: 240, flexGrow: 1, sortValue: item => moment(item.Since).format('L') },
    ]).current;

    const filterEmployee = (event: SyntheticEvent): void => {
        const { value } = event.target;
        const { payload } = props.unemployedEmployees;

        const newTableData = payload.filter((row: ISimpleEmployeeRowData): boolean =>
            (row.FirstName).toLowerCase().includes(value.toLowerCase()));

        setTableData(newTableData);
        setFilterText(value);
    };

    const rows = useMemo(() => {
        return tableData.map(entry => {
            return {
                data: [
                    { children: entry.FirstName },
                    { children: entry.LastName },
                    { children: entry.Since },

                ],

                onDoubleClick: (): void => props.goToEmployees(entry.ID),
                // Empty onClick will turn the hovering of table on
                onClick: () => {}
            };
        });
    }, [tableData]);

    useEffect(() => {
        if (props.unemployedEmployees.payload) {
            setTableData(props.unemployedEmployees.payload);
        }

        setFilterText('');
    }, [props.unemployedEmployees]);



    return (
        <VTable
           sortable
           striped
           rowHeight={36}
           headerColumns={headerColumns}
           rows={rows}
        />);
});

Here is used useRef,但我不确定它是否比在 RFC 之外声明它更好。

标签: javascriptreactjsclosuresreact-hooks

解决方案


将变量存储在功能组件中的最佳方式取决于您的用例。

在大多数情况下,您可以使用 useRef 钩子,因为它会在函数的每次渲染中返回相同的变量实例。

但是,您也可以使用 useMemo 挂钩定义变量并为其赋值。

喜欢

const val = useMemo(() => {
   return some calculation based value or in general a normal value
},[]) // dependency array to recalculate value

您必须注意 useRef 可以帮助您解决闭包问题,并且当您想要使用受闭包影响的变量时会派上用场。例如,在 useEffect 中定义的 setInterval 函数中使用闭包中的值,并且具有空依赖项。

另一方面,useMemo 将帮助您防止每次重新渲染的变量的引用更改。一个常见的用例是为 ContextProvider 提供一个记忆值

更新:

对于您的用例,有两种方法可以定义 headerColumns。

  • 在组件之外作为常数。当值预计不会改变时,将其声明为函数组件外部的常量是有意义的,也不需要使用闭包中的任何值

  • 作为函数内的记忆值

 const headerColumns = useMemo( () => [
        { children: 'First Name', width: 240, flexGrow: 1, sortValue: item => item.FirstName },
        { children: 'Last Name', width: 240, flexGrow: 1, sortValue: item => item.LastName },
        { children: 'Last day of employment', width: 240, flexGrow: 1, sortValue: item => moment(item.Since).format('L') },
    ], []);

当您使用闭包中的值时,您必须注意使用useMemo分配值headerColumns是有意义的。


推荐阅读