Giving the following code:
export const globalsSlice = createSlice({
name: 'globals',
initialState: {
testDirectories: {
dir_a: {
dir_a1: {},
dir_a2: {
dir_a2a: {}
}
}
}
},
reducers: {
updateDirectory: (state, action) => {
AddDirectorySubdir(state.testDirectories, action.payload.directoryName, action.payload.newSubDirectory);
return state;
}
}
});
function AddDirectorySubdir(tree, directoryName, newSubDirectory) {
for (var subDirectory in tree) {
if (subDirectory == directoryName) {
tree[subDirectory].newSubDirectory = {};
return true;
}
else if (AddDirectorySubdir(tree[subDirectory], directoryName, newSubDirectory))
break;
}
return false;
}
and:
function DirectoryDisplay(props) {
console.log("Refreshing " + props.directory);
function handleUpdateDirectory() {
let paylod = { directoryName: props.directory, newSubDirectory: "new_subDir" }
store.dispatch(updateDirectory(paylod));
}
let directoryStructure = [], subDirectoriesDepth = props.depth + 1;
directoryStructure.push(
<div id={props.directory} style={{ marginLeft: props.depth * 10, border: "1px solid black", width: "130px" }}>
{props.directory}
<button style={{ marginLeft: 10 }} onClick={() => handleUpdateDirectory()}>Update</button>
</div>
);
for (let subdirectory in props.subDirectories) {
directoryStructure.push(<DirectoryDisplay directory={subdirectory} subDirectories={props.subDirectories[subdirectory]} depth={subDirectoriesDepth}/>)
}
return directoryStructure;
}
export default function App() {
const testDirectories = useSelector(state => state.globals.testDirectories);
let rootDirectoryName = Object.keys(testDirectories)[0];
return (
<Fragment>
<DirectoryDisplay directory={rootDirectoryName} subDirectories={testDirectories[rootDirectoryName]} depth={0} />
</Fragment>
);
}
The output is as follows:
with the following console logs:
Refreshing dir_a
Refreshing dir_a1
Refreshing dir_a2
Refreshing dir_a2a
Then, when I click on the blued button, I got the desired following result:
with the following console logs:
Refreshing dir_a
Refreshing dir_a1
Refreshing dir_a2
Refreshing dir_a2a
Refreshing newSubDirectory
And there is what I was not expecting. the store state has changed, indeed, and the updating directory tree descends all the <DirectoryDisplay /> components as its hook is held by the root component. What I don't understand is that only the very last one "dir_a2a" has his content physically changed, so why are they all rerendered? Is there a way to prevent such a full rerendering? Should I manually consider a ComponentShouldUpdate() (or whatever it is for functional components) for each components?
If you have a tree and add a branch to a higher branch then the parent will re render but won't re render all children (only the one that changed).
You can use React.memo to make a functional component pure here is an example of a tree that only re renders things that change.