React 中使用的条件

Conditions in useEffect React

我有一个 useEffect 在启动时订阅 websocket 并将来自服务器的数据添加到 operationList 列表。该列表显示在网页上。这是施工设备执行的操作列表,我在网上收到,无法在后端更改。

useEffect(() => {
  const ws = new WebSocket('ws://127.0.0.1:8000/ws/')
  ws.addEventListener('message', (e) => {
    const response = JSON.parse(e.data)
      setOperationsList(operationsList => [
      response,
      ...operationsList,
    ]);

  })
  ws.onopen = () => {
    ws.send(JSON.stringify({
    action: "subscribe_to_operations_activity",
    request_id: new Date().getTime(),
  }))
  }
}, [])  

在同一个组件中,我有一个状态,它存储有关设备 ID 的信息,当前显示在屏幕上的报告。

const [activeID, setActiveID]  = useState(false)

我需要向 operationsList 添加的不是服务器中的所有数据,就像现在所做的那样 response = JSON.parse(e.data).相反,我需要检查条件 response.id == activeID,并仅将满足条件的数据添加到 operationsList。我无法将 activeID 添加到 useEffect 依赖项列表中,因为在这种情况下,每次 activeID 更改时都会创建一个新的 WebSocket 订阅。我知道很可能我不了解一些基本的东西,所以我将不胜感激任何建议

添加了 activeID 路径:

在我的组件中

const [activeID, setActiveID]  = useState(false)

  const getElementStar = (newID) => {
  setActiveID(newID)
}

然后我将它作为 props 传递给子组件:

<LeftMenu
  ...
  getElementStar={getElementStar}
  ...
/>

最后在子组件中

  const getKey = () => {
    const newID = props.item.id
    props.getElementStar(newID)
  }

  return (
    <ListItemButton sx={{ pl: 4 }} key={props.index} onClick={getKey}>
      <ListItemIcon>
        { props.star === props.index ? <Star/> : <StarBorder/> }
      </ListItemIcon>
      <ListItemText primary={props.item.name} />
    </ListItemButton>
  );

您可以尝试 运行 一个带有条件的循环,一旦为真,就会将您想要推送的内容推送到特定列表。仅当您从 back-end 接收的数据是一种数组类型时才有效。

let dataList = []

    const loopData = () => {
       e.data.forEach((obj) => {
         if (obj.id === activeID) {
            dataList.push(obj)
         } 
       }
    }

useEffect(() => loopData(), []);

然后

setOperationsList(...dataList)

activeID 应该如何改变? 基本上,将某些东西存储在状态中意味着当此值更改时组件需要 re-render。哪一个似乎不是你的情况?

所以我建议将您的 activeID 存储为 ref


const activeID = useRef('[my id]')

useEffect(() => {
  const ws = new WebSocket('ws://127.0.0.1:8000/ws/')
  ws.addEventListener('message', (e) => {
    const response = JSON.parse(e.data)
      
      setOperationsList(operationsList => [
      ...response.filter(o => o.id === activeID.current),
      ...operationsList,
    ]);

  })
  ws.onopen = () => {
    ws.send(JSON.stringify({
    action: "subscribe_to_operations_activity",
    request_id: new Date().getTime(),
  }))
  }
}, [])  

如果 activeID 需要以某种方式更改,您可以通过

useEffect(() => {
    activeID.current = [my new value]
}, [triggers that could change activeId (maybe a prop?)])

=== 编辑 ===

所以我假设更改 activeID 必须触发 re-render 以根据当前 activeID 更改您的 <Star > 组件,对吗? :)

所以我建议 2 个不同的东西。要么用ref,要么就是这样

const [activeID, setActiveID] = useState();
const activeIDRef = useRef()

useEffect

ws.addEventListener('message', (e) => {
    const response = JSON.parse(e.data)

      setOperationsList(operationsList => [
      ...response.filter(o => o.id === activeIDRef.current),
      ...operationsList,
    ]);
})

并有第二个 useEffectactiveID 更改时更改 ref

useEffect(() => {
    activeIDRef.current = activeID
}, [activeID])

也许继续将所有内容存储在 operationsList 中但在显示值时对其进行过滤会更容易。如果你需要这样的状态

const [operationsListFiltered, setOperationsListFiltered] = useState([]);
useEffect(() => {
    setOperationsListFiltered(operationsList.filter(o => o.id === activeId))
}, [activeId, operationsList])

或直接作为变量

const operationsListFiltered = useMemo(() => operationsList.filter(o => o.id === activeId), [activeId, operationsList]);

这样,您的 activeID 或您的 websocket 中的 operationLists 发生变化,您的 operationsListFiltered 将被更新