Lior Ehrlich
Lior Ehrlich

Reputation: 81

How to set initial state in 'useState' using a function?

I am building a table component. It gets as a prop an object called content which holds records that are displayed as the table's content. The component has a state called 'currentRecord' which holds the id of the selected row (changes in onClick event on each row). I want to set the first record's id to be the initial state using the 'useState'. As an initial state argument for the 'useState' it has a function which return the key(which is the id) of the first record in the content prop. But it returns undefined. When console logging the return value of that function, it return an id. Why does it return undefined when setting the initial state using a function?

I have tried setting the initial state using a string instead of a function, and it worked.

function getFirstOrderId(content:object): string {
    return Object.keys(content)[0];
}

const Table: FunctionComponent<Props> = props => {
  const { columnTitles, content, onRowClick } = props;
  const [currentRecord, setCurrentRecord] = useState(getFirstOrderId(content));
  useEffect(() => {
    onRowClick(currentRecord);
  }, [currentRecord]);
  return (
    <StyledTable>
      <thead>
        <tr>
          {Object.values(columnTitles).map(fieldName => {
            return <th>{fieldName}</th>;
          })}
        </tr>
      </thead>
      <StyledTBody>
        {mapWithKeys((order: any, id: string) => {
          return (
            <StyledRow
              key={id}
              isSelected={id === currentRecord}
              onClick={() => setCurrentRecord(id)}
              onDoubleClick={() => window.open("/" + order)}
            >
              {Object.keys(columnTitles).map(fieldContent => {
                return <td>{order[fieldContent]}</td>;
              })}
            </StyledRow>
          );
        }, content)}
      </StyledTBody>
    </StyledTable>
  );
};

export default Table;

Upvotes: 5

Views: 12773

Answers (3)

Rehan H
Rehan H

Reputation: 314

Put a function inside the useState hook and return the value.

const [value, setValue] = useState(() => ({key: "Param"}));
console.log(value) // output >> {key: "Param"}

Upvotes: 3

Tom Slutsky
Tom Slutsky

Reputation: 724

You can actually do lazy initialisation to state with a function. how ever you called the function and not passed in as a parameter, meaning you passed the returned value of the function as the initial value to use state. You can check out the official explanation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Upvotes: 0

cbdeveloper
cbdeveloper

Reputation: 31495

This might work:

const [currentRecord, setCurrentRecord] = useState(null);

useEffect(()=>{ // This will run after 1st render

  setCurrentRecord(getFirstOrderId(content)); // OPTION 1
  setCurrentRecord(()=>{                      // OPTION 2
    return getFirstOrderId(content);
  });

},[]);

You can set up a loading state to wait for the useEffect() to take place.

Upvotes: 2

Related Questions