最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to dynamically create objects in state with react hooks? - Stack Overflow

programmeradmin5浏览0评论

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?

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?

Share Improve this question edited Feb 20, 2019 at 10:34 jo_va 14k3 gold badges25 silver badges49 bronze badges asked Feb 20, 2019 at 10:19 cubefoxcubefox 1,30116 silver badges38 bronze badges 3
  • Why is it clunky to update? It's pretty close to what you would do with setState. – Estus Flask Commented Feb 20, 2019 at 10:38
  • 1 enumerated properties are awful, better use an array. And - is no valid character in a variable-name. [img-1, setImg-1] = ... – Thomas Commented Feb 21, 2019 at 6:53
  • those will be actual id's later on. What's the problem with the -? ist it just convention not to use it or does it cause problems? – cubefox Commented Feb 21, 2019 at 9:28
Add a ment  | 

1 Answer 1

Reset to default 8

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 ponent, 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 });
};
发布评论

评论列表(0)

  1. 暂无评论