简体   繁体   中英

How should I update individual items' className onClick in a list in a React functional component?

I'm new to React and I'm stuck trying to get this onClick function to work properly.

I have a component "Row" that contains a dynamic list of divs that it gets from a function and returns them:

export function Row({parentState, setParentState}) {
    let divList = getDivList(parentState, setParentState);
    
    return (
        <div>
            {divList}
        </div>
    )
}

Say parentState could just be:

[["Name", "info"],
["Name2", "info2"]]

The function returns a list of divs, each with their own className determined based on data in the parentState . Each one needs to be able to update its own info in parentState with an onClick function, which must in turn update the className so that the appearance of the div can change. My code so far seems to update the parentState properly (React Devtools shows the changes, at least when I navigate away from the component and then navigate back, for some reason), but won't update the className until a later event. Right now it looks like this:

export function getDivList(parentState, setParentState) {
//parentState is an array of two-element arrays

    const divList = parentState.map((ele, i) => {
        let divClass = "class" + ele[1];

        return (
            <div
                key={ele, i}
                className={divClass}
                onClick={() => {
                    let newParentState = 
                        JSON.parse(JSON.stringify(parentState);
                    newParentState[i][1] = "newInfo";

                    setParentState(newParentState);}}>
                {ele[0]}
            </div>
        )
    }
    return divList;
}

I have tried to use useEffect, probably wrong, but no luck. How should I do this?

Since your Row component has parentState as a prop, I assume it is a direct child of this parent component that contains parentState . You are trying to access getDivList in Row component without passing it as a prop, it won't work if you write your code this way.

You could use the children prop provided by React that allow you to write a component with an opening and closing tag: <Component>...</Component> . Everything inside will be in the children . For your code it would looks like this:

import React from 'react';
import { render } from 'react-dom';
import './style.css';

const App = () => {
  const [parentState, setParentState] = React.useState([
    ['I am a div', 'bg-red'],
    ['I am another div', 'bg-red'],
  ]);

  React.useEffect(
    () => console.log('render on ParentState changes'),
    [parentState]
  );

  const getDivList = () => {
    return parentState.map((ele, i) => {
      return (
        <div
          key={(ele, i)}
          className={ele[1]}
          onClick={() => {
            // Copy of your state with the spread operator (...)
            let newParentState = [...parentState];

            // We don't know the new value here, I just invented it for the example
            newParentState[i][1] = [newParentState[i][1], 'bg-blue'];

            setParentState(newParentState);
          }}
        >
          {ele[0]}
        </div>
      );
    });
  };

  return <Row>{getDivList()}</Row>;
};

const Row = ({ children }) => {
  return <>{children}</>;
};

render(<App />, document.getElementById('root'));

And a bit of css for the example:

.bg-red {
  background-color: darkred;
  color: white;
}

.bg-blue {
  background-color:aliceblue;
}

Here is a repro on StackBlitz so you can play with it.

I assumed the shape of the parentState , yu will have to adapt by your needs but it should be something like that.

Now, if your data needs to be shared across multiple components, I highly recommand using a context. Here is my answer to another post where you'll find a simple example on how to implement a context Api.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM