Search code examples
javascriptreactjsreact-hooksuse-statereact-usememo

useState doesn't update state passed in component


The SelectedColumn value doesn't come in the CustomHeader component. However, setSelectedColumn works! Why🧐 ? Also, I'm passing CustomHeader to constant components that use useMemo. Without useMemo CustomHeader doesn't work.

  const [selectedColumn, setSelectedColumn] = useState(null);
  console.log("selected Column Outside:", selectedColumn); // It works!

  const CustomHeader = (props) => {
    const colId = props.column.colId;

    console.log("selected Column In CustomHeader:", selectedColumn); // Doesn't work
    return (
      <div>
        <div style={{float: "left",  margin: "0 0 0 3px"}} onClick={() => setSelectedColumn(props.column.colId)}>{props.displayName}</div>
        { selectedColumn === colId ? <FontAwesomeIcon icon={faPlus} /> : null}
      </div>
    )
  }

  const components = useMemo(() => {
    return {
      agColumnHeader: CustomHeader
    }
  }, []);

UPDATE: If I use the useState hook inside the CustomHeader component, it adds a "+" sign to each column and does not remove from the previous one. Here is a picture:

enter image description here


Solution

  • After reading your comment, your issue is clearly about where you want to place your useState.

    First of all, you should always place useState inside a component. But in your case, apparently what you're trying to achieve is that when you select a column, the other columns get deselected.

    Therefore, you need to pass both selectedColumn and setSelectedColumn as props to your component, and create the useState on the parent component.

    Assuming all your CustomHeader components share the same parent component, in which my example I'll call CustomHeadersParent, you should do something like this:

    // added mock headers to have a working example
    const headers = [
      {
        displayName: "Game Name",
        column: {
          colId: 1,
        },
      },
      {
        displayName: "School",
        column: {
          colId: 2,
        },
      },
    ];
    
    const CustomHeadersParent = (props) => {
      const [selectedColumn, setSelectedColumn] = useState(null);
    
      return headers.map((h) => (
        <CustomHeader
          column={h.column}
          displayName={h.displayName}
          setSelectedColumn={setSelectedColumn}
          selectedColumn={selectedColumn}
        />
      ));
    };
    
    
    const CustomHeader = (props) => {
      const colId = props.column.colId;
    
      return (
        <div>
          <div
            style={{ float: "left", margin: "0 0 0 3px" }}
            onClick={() => props.setSelectedColumn(props.column.colId)}
          >
            {props.displayName}
          </div>
          {props.selectedColumn === colId ? <FontAwesomeIcon icon={faPlus} /> : null}
        </div>
      );
    };
    
    const components = useMemo(() => {
      return {
        agColumnHeader: CustomHeader,
      };
    }, []);