In my opinion, none of your examples has anything to do with actual dependency injection.
What you did here is structuring your lower level component TodoForm to depend on an abstraction — basically an interface with the properties name, isDone, onNameChange, onSubmit and onToggleDone.
That’s called Dependency Inversion — and it’s a good thing. But it’s not the same as Dependency Injection.
Dependency Injection would be the process of passing in concrete implementations for those defined properties — in OOP Terms it would be a concrete implementation object of the interface.
Now you can either do DI yourself in a client of the Component, implementing or delegating the concrete implementations / functions — or you can use a Framework that does this for you. The advantage of the latter is that you are able to configure what your component will do on a high level — outside of your actual application code.
For example: If you wanted to code against a Mock API instead of the real one during Development, you could configure your DI Container to pass a Mock-Function for onSubmit instead of a real one — without any if/else code Blocks and without changing ANY of your application code.