Somi
Somi

Reputation: 141

How can I update setState?

I'm trying to pass setChart to ChartType and i want to update setChart in ChartType component. so I tried to use array with null, but for some reason, I get this error : TypeError: setChart is not a function so How can I update setChart to change the chart with a different div ??

ChartTypePage

const ChartTypePage = ({ changeLayout }) => {
const [chart, setChart] = useState([
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
  ]);
  
  const layout = [
    <Side id="first" key="a" onClick={chartItself}>
      <ChartType visible={visible[0]} setChart={setChart[0]} />
      {chart[0]}
    </Side>,
    <Side id="second" key="b" onClick={chartItself}>
      <ChartType visible={visible[1]} setChart={setChart[1]} />
      {chart[1]}
    </Side>,
    <Side id="third" key="c" onClick={chartItself}>
      <ChartType visible={visible[2]} setChart={setChart[2]} />
      {chart[2]}
    </Side>,

ChartType

const ChartType = ({ visible, setChart }) => {
const chartType = [
    <Bar
      key="p"
      data={chartData}
      options={{ responsive: true, maintainAspectRatio: false }}
    />,
    <Line
      key="p"
      data={chartData}
      options={{ responsive: true, maintainAspectRatio: false }}
    />,
    <Radar
      key="p"
      data={chartData}
      options={{ responsive: true, maintainAspectRatio: false }}
    />]
    return (
    <TypeBox visible={visible}>
      <div>
        <div onClick={() => setChart(chartType[0])}>
          <h3>Line</h3>
        </div>
        <div onClick={() => setChart(chartType[1])}>
          <h3>Bar</h3>
        </div>
        <div onClick={() => setChart(chartType[2])}>
          <h3>Radar</h3>
        </div>
        <div onClick={() => setChart(chartType[3])}>
          <h3>Pie</h3>
        </div>
      </div>
    </TypeBox>
  );
};

export default ChartType;

Upvotes: 0

Views: 68

Answers (1)

Drew Reese
Drew Reese

Reputation: 202751

Issue

The issue here is that setChart in the ChartTypePage parent component is a function, so setChart[0] doesn't make any sense, it's undefined.

Solution

From what I can tell it seems like you want to pass a callback to the ChartType child component, setChart={setChart}. This is the state updater function that the children are invoking on click.

const layout = [
  <Side id="first" key="a" onClick={chartItself}>
    <ChartType visible={visible[0]} setChart={setChart} />
    {chart[0]}
  </Side>,
  ...
];

Update

In the child component you are mutating the state invariant from an array (where chart[i] is null) to the type of chartType[j]. You likely really want to update a specific index in the chart array.

Example:

<div
  onClick={() => setChart(charts => charts.map(
    (chart, i) => i === 0 ? chartType[0] : chart,
  )}
>
  <h3>Line</h3>
</div>

This will lead to a lot of code duplication since each onClick callback function will essentially be the same except for the index you want to update. Abstract this into a function and define it in the parent and pass instead of the setChart callback.

Example:

This is a curried function that first takes an index to close over in scope and return a function that then takes a char type to also close over in scope and then finally return a function to be used as the attached callback.

Note how the index is closed over when passing to the child, and then the child closes over the chart type.

const updateChart = index => chartType => () => {
  setChart(charts => charts.map(
    (chart, i) => i === index ? chartType : chart,
  );
};

...

const layout = [
  <Side id="first" key="a" onClick={chartItself}>
    <ChartType visible={visible[0]} setChart={updateChart(0)} />
    {chart[0]}
  </Side>,
  ...
];

Child

<div onClick={setChart(chartType[0])}>
  <h3>Line</h3>
</div>

Upvotes: 1

Related Questions