0

In my use case I have an array of characters, each character has multiple builds, and each build has a weapons string, and artifacts string. I'm making a tool to select portions of each string and assign them to a value, e.g. assigning index 3-49 of weapons to a specific weapon.

const [characterIndices, setCharacterIndices] = useState<
    { builds: { weaponIndices: SE[]; artifactSetIndices: SE[] }[] }[]
  >([
    ...characters.map((char) => {
      return {
        builds: [
          ...char.builds.map((_build) => {
            return {
              weaponIndices: [],
              artifactSetIndices: [],
            };
          }),
        ],
      };
    }),
  ]);

The SE type is as follows:

type SE = { start: number; end: number; code: string };
//start and end are the respective start and end of selected text
//code is the specific artifact or weapon

The weaponIndices and artifactSetIndices basically hold the start and end of selected text in a readonly textarea. I have a function to add a SE to either weaponIndices or artifactSetIndices:

const addSE = (
    type: "weaponIndices" | "artifactSetIndices",
    { start, end, code }: SE,
    characterIndex: number,
    buildIndex: number
  ) => {
    let chars = characterIndices;
    chars[characterIndex].builds[buildIndex][type].push({ start, end, code });
    setCharacterIndices((_prev) => chars);
    console.log(characterIndices[characterIndex].builds[buildIndex][type]);
  };

I think that using a console log after using a set function isn't recommended, but it does show what it's intended to the weaponIndices, or artifactSetIndices after an entry is added. Passing the addSE function alongside characterIndices to a separate component, and using addSE, does print the respective indices after adding an entry, but the component's rendering isn't updated.

It only shows up when I "soft reload" the page, when updating the files during the create-react-app live reload via npm run start.

In case you are confused about what the data types are, I've made a github repo, at https://github.com/ChrisMGeo/ght-indexer/tree/main/src at src/data.json. That JSON file describes what the character data looks like, including the builds, and each build's weapons and artifacts(called artifact_sets in the JSON)

2 Answers 2

1

Looks to me you are not updating the state at all. Here you are just storing the same object reference that you already have in state into a new variable chars.

let chars = characterIndices;

chars now holds reference to a same object as characterIndices.

Here you are mutating that same object

chars[characterIndex].builds[buildIndex][type].push({ start, end, code });

And here you are updating the state to the same object that is already in the state. Notice that no state update here occurs.

setCharacterIndices((_prev) => chars);

Object you have in state is mutated, but you did not "change" the value of the state, thus no component re-render.

What you could maybe do is create a copy of the object, mutate that and update the state. just change chars assignment like this:

 let chars = {...characterIndices};
Sign up to request clarification or add additional context in comments.

Comments

1

React often compares values using Object.is() only to a single level of nesting (the tested object and its children).

It will not re-render if the parent is found equal, or if all the children are found equal.

React then considers that nothing has changed.

In your implementation, even the first top-level check will immediately fail, since Object.is(before, after) will return true.

You could use an Immutable objects approach to eliminate this concern when setting a new state (either directly through spreading values or with a support library such as Immer).

For example instead of setting the values within the object...

myObj.key = newChildObj

...you would make a new object, which preserves many of the previous values.

myObj === {...myObj, key: newChildObj}

This means that every changed object tree is actually a different object (with only the bits that haven't changed being preserved).

To read more about this see https://javascript.plainenglish.io/the-effect-of-shallow-equality-in-react-85ae0287960c

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.