Forgetti
Forgetti (opens in a new tab) is also another alternative tool made to optimize React components at build time to make it run faster at runtime. But, when it comes to more complicated patterns, it generates failing code. For example, loops and mutations can lead to generating code that does not work.
Disclaimer: This comparison is not meant to degrade any of the tools. It's just a comparison of the features and limitations of the tools.
Feature | React Unforget | Forgetti |
---|---|---|
Basic components with no dependencies | ✅ | ✅ |
Basic components with dependencies | ✅ | ✅ |
Breaking down JSX | ✅ | ✖️ |
Basic mutation detection | ✅ | ✖️ |
Control flows | ✅ | Fails with while/for loops |
Example
Ok, let's see how Forgetti performs with a simple example. We have a counter component that uses the useState
hook. We will see how Forgetti handles this.
import { useState } from "react"; export default function CounterWithMutationTracking() { const [state, setState] = useState(0); const text = "Yay!"; return ( <div> <button onClick={() => setState(state + 1)}>Increment</button> <div> <span>Count: {state}</span> {text} </div> </div> ); }
export default function App() {
return <div>Compiling...</div>;
}
Read-onlyIt works for this simple case. Now let's make it a bit more complex. Remember the example from the home page of Unforget? Let's make the text
value mutable.
let text = "The count is is: ";
if (state % 2 === 0) {
text += "even";
} else {
text += "odd";
}
import { useState } from "react"; export default function CounterWithMutationTracking() { const [state, setState] = useState(0); let text = "The number is: "; if (state % 2 === 0) { text += "even"; } else { text += "odd"; } return ( <div> <button onClick={() => setState(state + 1)}>Increment</button> <div> <span>Count: {state}</span> {text} </div> </div> ); }
export default function App() {
return <div>Compiling...</div>;
}
Read-onlyAnd that just failed. Forgetti is not able to handle this. It's not able to detect the mutation in the text
variable. This is a limitation of Forgetti.
Now let's see how it handles loops.
import { useState } from "react"; const useData = () => { const [data, setData] = useState([]); return { data, addData: (item) => { setData([...data, item]); }, }; }; export default function CounterWithMutationTracking() { const { data, addData } = useData(); const filteredData = []; for (let i = 0; i < data.length; i++) { if (data[i] % 2 === 0) { filteredData.push(data[i]); } } return ( <div> <button onClick={() => addData(data.length)}>Add</button> <div> Data:{" "} {data.map((item) => ( <span key={item}>{item} </span> ))} </div> <div> Filtered data:{" "} {filteredData.map((item) => ( <span key={item}>{item} </span> ))} </div> </div> ); }
export default function App() {
return <div>Compiling...</div>;
}
Read-onlyIt fails again.
Ok, one more test. Let's see how it handles alias analysis.
import { useState } from "react"; function Comp({ a, b }) { const x = []; x.push(a); const y = x; y.push(b); return <div>n: {x.join(",")}</div>; } export default function App() { const [state, setState] = useState(1); return ( <div> {/* We use a constant value for a, but change b */} <Comp a={1} b={state} /> <button onClick={() => setState((p) => p + 1)}>click</button> </div> ); }
export default function App() {
return <div>Compiling...</div>;
}
Read-onlyIf you click on the button, you will see that the value is not updated.