admin管理员组

文章数量:1401491

Which is the best way to declare variables in React functional ponents (From now on - RFC)? It is not duplicate to Similar question this one.

As for me, there are a few ways of declaring variables `

  1. Declaring it with const inside RFC - If we pass this to the HeavyComponent ponent, so on each render, it will create a new reference, and HeavyComponent will render too. Not a good option.
  2. Declaring with useRef inside RFC - The reference will be the same within subsequent renders, which is good, but on the other hand, we are using useRef internal method (Function call - which does some job under the hood)
  3. Declaring with const outside of RFC (outer scope) - In this case, the reference will be again the same, as it will be taken from the closure and we don't use useRef method. But, in this particular case, we declare that variable in the outer scope and it is not being garbage collected and will cause memory leaks (if we use that cases very often).

I know, each case has its pros and cons. But when do we stick with a certain option?

UPDATED Here is the example

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, but I am not sure if it's better than just declaring it outside of RFC.

Which is the best way to declare variables in React functional ponents (From now on - RFC)? It is not duplicate to Similar question this one.

As for me, there are a few ways of declaring variables `

  1. Declaring it with const inside RFC - If we pass this to the HeavyComponent ponent, so on each render, it will create a new reference, and HeavyComponent will render too. Not a good option.
  2. Declaring with useRef inside RFC - The reference will be the same within subsequent renders, which is good, but on the other hand, we are using useRef internal method (Function call - which does some job under the hood)
  3. Declaring with const outside of RFC (outer scope) - In this case, the reference will be again the same, as it will be taken from the closure and we don't use useRef method. But, in this particular case, we declare that variable in the outer scope and it is not being garbage collected and will cause memory leaks (if we use that cases very often).

I know, each case has its pros and cons. But when do we stick with a certain option?

UPDATED Here is the example

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, but I am not sure if it's better than just declaring it outside of RFC.

Share Improve this question edited Jun 7, 2020 at 12:13 Norayr Ghukasyan asked Jun 7, 2020 at 11:40 Norayr GhukasyanNorayr Ghukasyan 1,4182 gold badges19 silver badges39 bronze badges 5
  • What kind of answer you are looking for? What are the use cases for each? As if you know the props/cons it bees opinioned question – Dennis Vash Commented Jun 7, 2020 at 11:57
  • 1 If you pay attention to my title and also to the bottom of the question , there I mentioned what I need . What is the best way to do it and I am sure , there are cases , that one if them is preferable – Norayr Ghukasyan Commented Jun 7, 2020 at 11:59
  • So what is the use case? Do you have any particular one and you don't know what you should do? – Dennis Vash Commented Jun 7, 2020 at 12:01
  • I have used all of them, but don't know which one is better in certain cases – Norayr Ghukasyan Commented Jun 7, 2020 at 12:02
  • Thats what I'm trying to say, show us the certain cases, in Stackoverflow, as you know, that's kind of question that should be asked. I can e up with cases, but they will be arbitrary. See How do I ask a good question? – Dennis Vash Commented Jun 7, 2020 at 12:03
Add a ment  | 

2 Answers 2

Reset to default 4

The best way to store variables in a functional ponent depends on your useCase.

In most cases you can make use of useRef hook since it returns you the same instance of the variable on each render of the function.

You can however define a variable and assign its value using useMemo hook too.

like

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

You must note that useRef helps you get around closure issues and es in handy when you want to use variables that are affected by closure. For instance using a value from closure inside a setInterval function defined within useEffect with empty dependency.

On the other hand useMemo will help you prevent references change for variables no each re-render. A mon useCase of this would be to provide a memoized value for ContextProvider

UPDATE:

For your usecase, there are two ways to define headerColumns.

  • Outside of the ponent as a constant. Declaring it as a constantoutside of the functional ponent makes sense when the value is not expected to change, nor is it expected to use any value from the closure

  • As a memozied value within the function

 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') },
    ], []);

You must note the using useMemo to assign value to headerColumns makes sense when you use value from closure.

In your use-case, headerColumns should be in outer scope:

const headerColumns = [
  {
    children: "First Name",
    width: 240,
    flexGrow: 1,
    sortValue: (item) => item.FirstName,
  },
  // more
];

export const UnemployedEmployeesReportPaper = React.memo((props) => {});

If its a "read-only" object, it should be in the outer scope.

See Why need useRef to contain mutable variable but not define variable outside the ponent function?.

In your current situation, if you have N UnemployedEmployeesReportPaper ponents, you will have N headerColumns references, instead on outer scope all ponents will share the same immutable object (immutable because in your use case, it acts as read-only object).

本文标签: javascriptWhat is the best way to declare static variables in React functional componentsStack Overflow