Reputation: 1301
until now in my code, I had an object that would represent all the data for an image on the page
this.state = {
img-1: {
x: 0,
y: 0,
rotation: 0
},
img-2: {
x: 20,
y: 200,
rotation: 50
}
}
every time the object receives a new child it adds a new img-id
to state that is updated everytime <img id=${id} update={this.update} />
is updated.
Moving functionality like calculating the coordinates or the rotation into their own custom hooks would greatly improve my code in terms of maintainability and testing but I don't really see a good way to store all of this data in a centralized object with hooks.
As far as I understand it I'd have to set either a new
[img-1, setImg-1] = useState({ x: 0, y:0, rotation: 0 })
for every child which, as I understand it, isn't possible as hooks have to be declared at the top level or to set a very deep object that would be kind of clunky to update:
[images, setImages] = useState({
img-1: {
x: 0,
y: 0,
rotation: 0
}
})
const createImg = (newImg) => { setImages({...images, newImg}) }
const updateImg = (id, updatedImg) => {
setImages({ ...images, [`img-${id}`]{...updatedImg} }
)}
Is there a cleaner / more readable approach or do I just have to resort to nesting everything in one object?
Upvotes: 4
Views: 8047
Reputation: 281636
Instead of using a useState
, you can make use of useReducer
and control your states better and handle dynamic addition of states.
const initialState = {
'img-1': {
x: 0,
y: 0,
rotation: 0,
},
};
const reducer = (state, action) => {
switch (action.type) {
case 'ADD_IMAGE':
return {
...state,
[action.itemkey]: action.payload,
};
case 'UPDATE_IMAGE':
return {
...state,
[action.id]: { ...state[action.id], ...action.payload },
};
default: {
return state;
}
}
};
In case you're using a functional component, the code then looks as follows.
const [state, dispatch] = useReducer(reducer, initialState);
const createImg = (newImg) => {
dispatch({
type: 'ADD_IMAGE',
payload: { newImg },
itemKey: `item-${Object.keys(state).length + 1}`,
});
};
const updateImg = (id, updatedImg) => {
dispatch({ type: 'UPDATE_IMAGE', id, payload: updatedImg });
};
Upvotes: 8