在 useEffect 中使用 useState 值而不使状态更新 useEffect
Use useState value in useEffect without making the state update useEffect
我正在开发一个基于对象键管理字符串数组的函数。假设它看起来像这样:
import React, { useState, useEffect } from "react";
import FieldContext from "../contexts/FieldContext";
import io from "socket.io-client";
const [socket, setSocket] = useState(null);
// the `data` array gets changed every second due to a WebSocket, in case that's important
const [data, setData] = useState({ foo: [], bar: [] });
const [connections, setConnections] = useState(["conn1", "conn2"]);
const { checkedFields } = useContext(FieldContext); // ["foo", "moo"];
useEffect(() => {
setConnections(prevConnections => {
// The code below does the following:
// Loop through the temporary connections (which is a copy of checkedFields)
// A. if `tempConn` is a key in the `data` object, push the name with `update_` prefix to the `_conns` array
// B. If not, just push it without a prefix to the `_conns` array
// Since the `checkedFields` array is ["foo", "moo"], the first element will get the prefix,
// the other won't and will just get pushed.
let _tempConns = [...checkedFields];
let _conns = [];
_tempConns.forEach(tempConn => {
if (data[tempConn] !== undefined) _conns.push(`update_${tempConn}`);
else _conns.push(tempConn);
});
return _conns;
});
}, [checkedFields]);
// the websocket hook
useEffect(() => {
const _socket = io(WS_URI);
_socket.on("info", data => {
// some magic happens here to add to the `data` object which is not important for this question
});
setSocket(_socket);
}, [])
我在使用此挂钩时收到以下警告:React Hook useEffect has a missing dependency: 'data'. Either include it or remove the dependency array
。据我所知,但是如果我在依赖数组中包含 data
,我会得到大量不必要的更新。我如何防止这种情况发生? (请不要使用 // eslint-disable-next-line
)
您不仅缺少 useEffect
挂钩的依赖数组中的 data
,而且还缺少依赖数组中的 setConnections()
函数。
您可以使用 useReducer
挂钩将状态更新逻辑移出 useEffect
挂钩。
const initialState = {
data: { foo: [], bar: [] },
connections: ["conn1", "conn2"]
}
const reducerFunc = (state, action) => {
switch(action.type) {
case 'UPDATE_CONNECTIONS':
let _tempConns = [...action.checkedFields];
let _conns = [];
_tempConns.forEach(tempConn => {
if (state.data[tempConn] !== undefined) _conns.push(`update_${tempConn}`);
else _conns.push(tempConn);
});
return { ...state, connections: _conns };
default:
return state;
}
};
const [myState, dispatch] = useReducer(reducerFunc, initialState);
const { checkedFields } = useContext(FieldContext); // ["foo", "moo"];
useEffect(() => {
dispatch({ type: 'UPDATE_CONNECTIONS', payload: checkedFields });
}, [checkedFields]);
由于 React 确保 dispatch
函数不会改变,您可以从 useEffect
钩子的依赖数组中省略它。
有关如何使用 useReducer
挂钩的详细信息,请参阅以下链接:
可以尝试使用 useRef
如果您可以在您的 websocket 中摆脱以下问题并且没有其他 useEffect
指望 data
参考
useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
// make `data` a ref object
// Pitfall: any changes to `data.current` will NOT be tracked
const data = useRef({ foo: [], bar: [] })
// the websocket hook
useEffect(() => {
...
_socket.on("info", data => {
...
// update properties on `data.current`
data.current.foo = 'some new value'
data.current.bar = 'anoher new value;
});
...
}, [])
useEffect(() => {
setConnections(prevConnections => {
...
// reference data value from data.current
const data = data.current
...
return _conns;
});
}, [checkedFields])
随着您的更新,您的套接字似乎永远不会关闭。
如果您的组件卸载/重新安装,您将在后台添加一个新套接字。
然后在每次更新时,它都会触发所有以前的套接字。
您的套接字钩子应该return 关闭套接字函数。 (我猜,我从来没有直接使用socket)
useEffect(() => {
const _socket = io(WS_URI);
_socket.on("info", data => {
// some magic happens here to add to the `data` object which is not important for this question
});
setSocket(_socket);
return () => {_socket.close();}
}, [])
(这不是您的回答的回应,但它可以提供帮助:))
我正在开发一个基于对象键管理字符串数组的函数。假设它看起来像这样:
import React, { useState, useEffect } from "react";
import FieldContext from "../contexts/FieldContext";
import io from "socket.io-client";
const [socket, setSocket] = useState(null);
// the `data` array gets changed every second due to a WebSocket, in case that's important
const [data, setData] = useState({ foo: [], bar: [] });
const [connections, setConnections] = useState(["conn1", "conn2"]);
const { checkedFields } = useContext(FieldContext); // ["foo", "moo"];
useEffect(() => {
setConnections(prevConnections => {
// The code below does the following:
// Loop through the temporary connections (which is a copy of checkedFields)
// A. if `tempConn` is a key in the `data` object, push the name with `update_` prefix to the `_conns` array
// B. If not, just push it without a prefix to the `_conns` array
// Since the `checkedFields` array is ["foo", "moo"], the first element will get the prefix,
// the other won't and will just get pushed.
let _tempConns = [...checkedFields];
let _conns = [];
_tempConns.forEach(tempConn => {
if (data[tempConn] !== undefined) _conns.push(`update_${tempConn}`);
else _conns.push(tempConn);
});
return _conns;
});
}, [checkedFields]);
// the websocket hook
useEffect(() => {
const _socket = io(WS_URI);
_socket.on("info", data => {
// some magic happens here to add to the `data` object which is not important for this question
});
setSocket(_socket);
}, [])
我在使用此挂钩时收到以下警告:React Hook useEffect has a missing dependency: 'data'. Either include it or remove the dependency array
。据我所知,但是如果我在依赖数组中包含 data
,我会得到大量不必要的更新。我如何防止这种情况发生? (请不要使用 // eslint-disable-next-line
)
您不仅缺少 useEffect
挂钩的依赖数组中的 data
,而且还缺少依赖数组中的 setConnections()
函数。
您可以使用 useReducer
挂钩将状态更新逻辑移出 useEffect
挂钩。
const initialState = {
data: { foo: [], bar: [] },
connections: ["conn1", "conn2"]
}
const reducerFunc = (state, action) => {
switch(action.type) {
case 'UPDATE_CONNECTIONS':
let _tempConns = [...action.checkedFields];
let _conns = [];
_tempConns.forEach(tempConn => {
if (state.data[tempConn] !== undefined) _conns.push(`update_${tempConn}`);
else _conns.push(tempConn);
});
return { ...state, connections: _conns };
default:
return state;
}
};
const [myState, dispatch] = useReducer(reducerFunc, initialState);
const { checkedFields } = useContext(FieldContext); // ["foo", "moo"];
useEffect(() => {
dispatch({ type: 'UPDATE_CONNECTIONS', payload: checkedFields });
}, [checkedFields]);
由于 React 确保 dispatch
函数不会改变,您可以从 useEffect
钩子的依赖数组中省略它。
有关如何使用 useReducer
挂钩的详细信息,请参阅以下链接:
可以尝试使用 useRef
如果您可以在您的 websocket 中摆脱以下问题并且没有其他 useEffect
指望 data
参考
useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
// make `data` a ref object
// Pitfall: any changes to `data.current` will NOT be tracked
const data = useRef({ foo: [], bar: [] })
// the websocket hook
useEffect(() => {
...
_socket.on("info", data => {
...
// update properties on `data.current`
data.current.foo = 'some new value'
data.current.bar = 'anoher new value;
});
...
}, [])
useEffect(() => {
setConnections(prevConnections => {
...
// reference data value from data.current
const data = data.current
...
return _conns;
});
}, [checkedFields])
随着您的更新,您的套接字似乎永远不会关闭。 如果您的组件卸载/重新安装,您将在后台添加一个新套接字。 然后在每次更新时,它都会触发所有以前的套接字。
您的套接字钩子应该return 关闭套接字函数。 (我猜,我从来没有直接使用socket)
useEffect(() => {
const _socket = io(WS_URI);
_socket.on("info", data => {
// some magic happens here to add to the `data` object which is not important for this question
});
setSocket(_socket);
return () => {_socket.close();}
}, [])
(这不是您的回答的回应,但它可以提供帮助:))