I have various versions of useCrudState hook around but never published a
package of it. I used ChatGPT to see how far I can
get and what the experience is by "just dictating".
I needed multiple sessions since at some point ChatGPT got stuck middle-way and stopped outputting. In between sessions, I sometimes reordered or do some cosmetics that I would do faster.
While Functional Programming teaches you to focus on more "what" as oposed to
"how", working together with ChatGPT takes this to a different level.
You tell it to do something and it does it but not exactly how you expected or
wanted. You re-read your instructions and realize that you were not clear
enough or just a wrong comma. You rephrase and realize your reasoning was
crooked, used to many words etc. You go back 3 questions and reshape your
argument. This is the ultimate rubber ducking, when the duck answers back and
helps you obtain a better resolution on the overall chain/funnel of
transformation.
Overall, I cant wait for other interfaces to emerge. Copilot is great but it's still at the snippet level and I dont think there are any inherent limitations to the tech to not work at a project level. For ex. coding in your editor while also telling it to "install and setup babel", "switch to swc" or "similar to the admin section of Users, write the pages for Todos" etc.
Resulting code at https://github.com/asd-xiv/use-crud-state
Q1: Generate a React Hook called
useCrudState, similar with the nativeuseStatehook, that gives the ability of editing the internal array state through all the CRUD methods instead ofuseStatejust one method.
Certainly! Here is an example of how you could implement a useCrudState hook in React:
import { useState } from 'react';
function useCrudState(initialState) {
const [state, setState] = useState(initialState);
function add(item) {
setState([...state, item]);
}
function remove(index) {
setState([...state.slice(0, index), ...state.slice(index + 1)]);
}
function update(index, item) {
setState([...state.slice(0, index), item, ...state.slice(index + 1)]);
}
return [state, { add, remove, update }];
}This hook works just like the native useState hook, but instead of just providing a setter function for updating the state, it also provides add, remove, and update functions for performing CRUD operations on the state.
You can use this hook in your React components like this:
import { useCrudState } from './useCrudState';
function MyComponent() {
const [items, { add, remove, update }] = useCrudState([]);
// use add, remove, and update to perform CRUD operations on the items state
}I hope this helps! Let me know if you have any questions.
Q2: Use only arrow functions, rename
addtocreateand instead of exposing the raw items array, use selectors for accessing all the items.
Certainly! Here is an updated version of the useCrudState hook that uses arrow functions and exposes selectors for accessing the items in the state:
import { useState } from 'react';
const useCrudState = initialState => {
const [state, setState] = useState(initialState);
const create = item => {
setState([...state, item]);
};
const remove = index => {
setState([...state.slice(0, index), ...state.slice(index + 1)]);
};
const update = (index, item) => {
setState([...state.slice(0, index), item, ...state.slice(index + 1)]);
};
const all = () => state;
return [{ create, remove, update }, { all }];
};This hook works just like the previous version, but it uses arrow functions instead of regular functions, and it exposes selectors for accessing the items in the state.
You can use this hook in your React components like this:
import { useCrudState } from './useCrudState';
function MyComponent() {
const [{ create, remove, update }, { all }] = useCrudState([]);
// use create, remove, and update to perform CRUD operations on the state
// use the all selector to access all the items in the state
}I hope this helps! Let me know if you have any questions.
Q3: Reorder the selector and setters, first the selectors, similar to how React's
useState.
Certainly! Here is an updated version of the useCrudState hook that reorders the selectors and setters, so that the selectors are first, similar to how the useState hook works:
import { useState } from 'react';
const useCrudState = initialState => {
const [state, setState] = useState(initialState);
const all = () => state;
const create = item => {
setState([...state, item]);
};
const remove = index => {
setState([...state.slice(0, index), ...state.slice(index + 1)]);
};
const update = (index, item) => {
setState([...state.slice(0, index), item, ...state.slice(index + 1)]);
};
return [all, { create, remove, update }];
};This hook works just like the previous versions, but it reorders the selectors and setters so that the selectors are first.
You can use this hook in your React components like this:
import { useCrudState } from './useCrudState';
function MyComponent() {
const [all, { create, remove, update }] = useCrudState([]);
// use all to access all the items in the state
// use create, remove, and update to perform CRUD operations on the state
}Q4: Update the hook to expect the state is composed of only objects that always have an
idfield. Update theremoveandupdatesetters to work based on theidfield.
Certainly! Here is an updated version of the useCrudState hook that expects the state to be composed of objects with an id field, and that updates the remove and update setters to work based on the id field:
import { useState } from 'react';
const useCrudState = initialState => {
const [state, setState] = useState(initialState);
const all = () => state;
const create = item => {
setState([...state, item]);
};
const remove = id => {
setState(state.filter(item => item.id !== id));
};
const update = (id, update) => {
setState(
state.map(item => (item.id === id ? { ...item, ...update } : item))
);
};
return [all, { create, remove, update }];
};This hook works just like the previous versions, but it expects the state to be composed of objects with an id field, and it updates the remove and update setters to work based on the id field.
You can use this hook in your React components like this:
import { useCrudState } from './useCrudState';
function MyComponent() {
const [all, { create, remove, update }] = useCrudState([]);
// use all to access all the items in the state
// use create, remove, and update to perform CRUD operations on the state
}I hope this helps! Let me know if you have any questions.
Q5: Add another selector that allows retrieving an item by
id.
Certainly! Here is an updated version of the useCrudState hook that also includes a selector for retrieving an item by id:
import { useState } from 'react';
const useCrudState = initialState => {
const [state, setState] = useState(initialState);
const all = () => state;
const getById = id => state.find(item => item.id === id);
const create = item => {
setState([...state, item]);
};
const remove = id => {
setState(state.filter(item => item.id !== id));
};
const update = (id, update) => {
setState(
state.map(item => (item.id === id ? { ...item, ...update } : item))
);
};
return [all, { create, remove, update, getById }];
};This hook works just like the previous versions, but it also includes a getById selector for retrieving an item by its id field.
You can use this hook in your React components like this:
import { useCrudState } from './useCrudState';
function MyComponent() {
const [all, { create, remove, update, getById }] = useCrudState([]);
// use all to access all the items in the state
// use create, remove, and update to perform CRUD operations on the state
// use getById to retrieve an item by its id
}I hope this helps! Let me know if you have any questions.
Q6: Keep all selectors and setters grouped in separate objects from now on.
Certainly! Here is an updated version of the useCrudState hook that keeps all the selectors and setters grouped in separate objects:
import { useState } from 'react';
const useCrudState = initialState => {
const [state, setState] = useState(initialState);
const selectors = {
all: () => state,
getById: id => state.find(item => item.id === id)
};
const setters = {
create: item => {
setState([...state, item]);
},
remove: id => {
setState(state.filter(item => item.id !== id));
},
update: (id, update) => {
setState(
state.map(item => (item.id === id ? { ...item, ...update } : item))
);
}
};
return [selectors, setters];
};This hook works just like the previous versions, but it keeps all the selectors and setters grouped in separate objects.
You can use this hook in your React components like this:
import { useCrudState } from './useCrudState';
function MyComponent() {
const [selectors, setters] = useCrudState([]);
// use selectors.all to access all the items in the state
// use setters.create, setters.remove, and setters.update to perform CRUD operations on the state
// use selectors.getById to retrieve an item by its id
}I hope this helps! Let me know if you have any questions.
Q7: From now on, skip the 2nd code sample, the how to use the hook example, keep your answers as short as possible, unless I ask you to explain.
Certainly! I apologize for the lengthy explanations. From now on, I will skip the second code sample (the example of how to use the hook in a React component) and keep my answers as short as possible, unless you ask me to explain something in more detail.
Here is the updated version of the useCrudState hook that keeps all the selectors and setters grouped in separate objects:
import { useState } from 'react';
const useCrudState = initialState => {
const [state, setState] = useState(initialState);
const selectors = {
all: () => state,
getById: id => state.find(item => item.id === id)
};
const setters = {
create: item => {
setState([...state, item]);
},
remove: id => {
setState(state.filter(item => item.id !== id));
},
update: (id, update) => {
setState(
state.map(item => (item.id === id ? { ...item, ...update } : item))
);
}
};
return [selectors, setters];
};I hope this helps! Let me know if you have any questions.
Q8: Update the
createsetter to throw an error if an item with the sameidalready exists.
Certainly! Here is an updated version of the useCrudState hook that includes an error check in the create setter to ensure that an item with the same id does not already exist:
import { useState } from 'react';
const useCrudState = initialState => {
const [state, setState] = useState(initialState);
const selectors = {
all: () => state,
getById: id => state.find(item => item.id === id)
};
const setters = {
create: item => {
if (state.find(i => i.id === item.id)) {
throw new Error(`Item with id ${item.id} already exists`);
}
setState([...state, item]);
},
remove: id => {
setState(state.filter(item => item.id !== id));
},
update: (id, update) => {
setState(
state.map(item => (item.id === id ? { ...item, ...update } : item))
);
}
};
return [selectors, setters];
};This hook works just like the previous versions, but it includes an error check in the create setter to ensure that an item with the same id does not already exist. If an item with the same id already exists, the create setter will throw an error.
I hope this helps! Let me know if you have any questions.
Q9: Now do the same with
removebut check if the item is not preset.
Certainly! Here is an updated version of the useCrudState hook that includes an error check in the remove setter to ensure that the item to be removed exists:
import { useState } from 'react';
const useCrudState = initialState => {
const [state, setState] = useState(initialState);
const selectors = {
all: () => state,
getById: id => state.find(item => item.id === id)
};
const setters = {
create: item => {
if (state.find(i => i.id === item.id)) {
throw new Error(`Item with id ${item.id} already exists`);
}
setState([...state, item]);
},
remove: id => {
if (!state.find(i => i.id === id)) {
throw new Error(`Item with id ${id} not found`);
}
setState(state.filter(item => item.id !== id));
},
update: (id, update) => {
setState(
state.map(item => (item.id === id ? { ...item, ...update } : item))
);
}
};
return [selectors, setters];
};This hook works just like the previous versions, but it includes an error check in the remove setter to ensure that the item to be removed exists. If the item does not exist, the remove setter will throw an error.
I hope this helps! Let me know if you have any questions.
Q10: Create a
hasWithIdpure function and use it where ever an existence check is required.
Certainly! Here is an updated version of the useCrudState hook that includes a hasWithId pure function for checking if an item with a given id exists in the state, and that uses this function wherever an existence check is required:
import { useState } from 'react';
const useCrudState = initialState => {
const [state, setState] = useState(initialState);
const hasWithId = id => state.some(item => item.id === id);
const selectors = {
all: () => state,
getById: id => state.find(item => item.id === id)
};
const setters = {
create: item => {
if (hasWithId(item.id)) {
throw new Error(`Item with id ${item.id} already exists`);
}
setState([...state, item]);
},
remove: id => {
if (!hasWithId(id)) {
throw new Error(`Item with id ${id} not found`);
}
setState(state.filter(item => item.id !== id));
},
update: (id, update) => {
setState(
state.map(item => (item.id === id ? { ...item, ...update } : item))
);
}
};
return [selectors, setters];
};This hook works just like the previous versions, but it includes a hasWithId function for checking if an item with a given id exists in the state, and it uses this function wherever an existence check is required.
I hope this helps! Let me know if you have any questions.
Q11: Write a short paragraph describing the
useCrudStatehook and a 2 point bullet list with it's features: CRUD operations, Error handling. Make an analogy to the ReactuseState. Be succinct.
The useCrudState hook is a custom React hook that provides state management
functionality similar to the built-in useState hook, but with the added ability
to perform CRUD (create, read, update, delete) operations on the state. It
exposes selectors for accessing the items in the state and setters for
performing CRUD operations on the state. It also includes error handling to
ensure that the setters are used correctly.
Features:
- CRUD operations:
create,remove,updatesetters for adding, deleting, and updating items in the state - Error handling: checks to ensure that items being added or deleted actually exist, and throws errors if they do not
The useCrudState hook is an useful tool for managing state in React components
that require more advanced state management capabilities than those provided by
the built-in useState hook.
Q12: Write an example of the hooks functionalities using an initial state of 3 todo items.
Certainly! Here is an example of how you might use the useCrudState hook to manage a state of todo items in a React component:
import { useCrudState } from './useCrudState';
function TodoList() {
const initialState = [
{ id: 1, text: 'Take out the trash', completed: false },
{ id: 2, text: 'Do the dishes', completed: false },
{ id: 3, text: 'Buy milk', completed: true }
];
const [selectors, setters] = useCrudState(initialState);
const handleAddTodo = e => {
e.preventDefault();
const text = e.target.elements.todoText.value;
setters.create({ id: Date.now(), text, completed: false });
};
const handleDeleteTodo = id => {
setters.remove(id);
};
const handleToggleTodo = id => {
const todo = selectors.getById(id);
setters.update(id, { completed: !todo.completed });
};
return (
<div>
<form onSubmit={handleAddTodo}>
<input type="text" name="todoText" />
<button type="submit">Add Todo</button>
</form>
<ul>
{selectors.all().map(todo => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => handleToggleTodo(todo.id)}
/>
{todo.text}
<button onClick={() => handleDeleteTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}