From bcb1bd5f6fe5116227a774b8c844163139cf6c24 Mon Sep 17 00:00:00 2001 From: li3zhen1 Date: Fri, 23 Feb 2024 00:08:56 -0500 Subject: [PATCH] [Doc] Add State Management and Eliminating Redundant Rerenders --- Sources/Grape/Grape.docc/Documentation.md | 1 + ...agementAndEliminatingRedundantRerenders.md | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 Sources/Grape/Grape.docc/StateManagementAndEliminatingRedundantRerenders.md diff --git a/Sources/Grape/Grape.docc/Documentation.md b/Sources/Grape/Grape.docc/Documentation.md index 22e7585..64bcb31 100644 --- a/Sources/Grape/Grape.docc/Documentation.md +++ b/Sources/Grape/Grape.docc/Documentation.md @@ -22,6 +22,7 @@ Grape supports localization features. You can localize the labels in the graph v * +* * ``ForceDirectedGraph`` diff --git a/Sources/Grape/Grape.docc/StateManagementAndEliminatingRedundantRerenders.md b/Sources/Grape/Grape.docc/StateManagementAndEliminatingRedundantRerenders.md new file mode 100644 index 0000000..55e5f25 --- /dev/null +++ b/Sources/Grape/Grape.docc/StateManagementAndEliminatingRedundantRerenders.md @@ -0,0 +1,77 @@ +# State Management and Eliminating Redundant Rerenders + + + +## Control the state + +You can control the view state like this: + +```swift +import Grape + +struct MyStatefulGraph: View { + + // States including running status, transformation, etc. + // Gives you a handle to control the states. + @State var graphStates = ForceDirectedGraphState() + + var body: some View { + ForceDirectedGraph(states: graphStates) { + // ... + } force: { + // ... + } + } +} +``` + +`ForceDirectedGraphState` utilizes the `Observation` framework so all you need to change the state is to mutate its properties: + +```swift + +graphStates.isRunning.toggle() + +graphStates.transform = .identity // reset transform to identity + +``` + +## Eliminate redundant rerenders + +One trick to eliminate redundant rerenders is to not referencing any observed properties in the `body` of the `View`. Instead, try to reference the entire `Observable` object. This way, the `body` will not rerender when the observed properties change. + +```swift +import Grape + +struct MyStatefulGraph: View { + + // States including running status, transformation, etc. + // Gives you a handle to control the states. + @State var graphStates = ForceDirectedGraphState() + + var body: some View { + HStack { + ForceDirectedGraph(states: graphStates) { + // ... + } force: { + // ... + } + GraphStateToggle(graphStates: graphStates) // seperate views so we can reference the entire graphStates + } + } +} + +struct GraphStateToggle: View { + @Bindable var graphStates: ForceDirectedGraphState + var body: some View { + Button { + graphStates.isRunning.toggle() + } label: { + // ... + } + } +} +``` + +Although this introduces boilerplates, but `Grape` do benifit from this pattern since its re-evaluation is expensive (especially with large graphs or heavy rich text labels). + +> This might not always work for other `Observation` based state management. \ No newline at end of file