user6329530
user6329530

Reputation: 734

How can I use variables in useEffect without having them in a dependency?

I have an objectList and a size variable.

const [objectList, setObjectList] = useState([]); //will be filled elsewhere
const [size, setSize] = useState([props.width, props.height]); //might change on user input

useEffect(() => {
    //When size changes iterate over objectList
    objectList.forEach(object => {
        object.set({
            width: size.width,
            height: size.height
        );
    });
}, [size]);

Here React complains, that objectList is not in dependency, because it might be, that I want to depend the useEffect on objectList changes. However I don't. Objects can be added to the list occasionally but in this case I am setting size where the object will be added to the list. I do not want to iterate over every object when I add a new object to the list (objectList changed), only when the size changed.

How can I iterate over the objectList on each size change but not on objectList change?

Upvotes: 5

Views: 1228

Answers (2)

Joseph D.
Joseph D.

Reputation: 12174

There seems to be two actions affecting the objectList: on size change and when new object is added. You need to separate these two.

You can achieve this via useReducer to manage the different actions.

const initialState = {
  objectList: []
}

function reducer(state, action) {
  switch (action.type) {
    case 'ADD_OBJECT': /* TODO */ return;
    case 'UPDATE_SIZE': {
       const { size } = action.payload;
       return state.objectList.map((o) => ({
         ...o,
         width: size.width,
         height: size.height
       }))
    }
    default: /* TODO */;
  }
}

function App(props) {
  const [state, dispatch] = useReducer(reducer, initialState);

  useEffect(() => {
    dispatch({
      type: 'UPDATE_SIZE',
      payload: {
        size: {
          width: props.width,
          height: props.height
        }
      }
    });
  }, [props.size]);
}

Upvotes: 1

Ravi MCA
Ravi MCA

Reputation: 2621

I ended up doing this and it worked.

useEffect(() => {
    setObjectList((objectList)=>{
        objectList.forEach(object => {
            object.set({
                width: size.width,
                height: size.height
            );
        });
    
        return objectList;
    });
}, [size]);

Upvotes: 1

Related Questions