首页 > 解决方案 > 反应上下文不更新组件

问题描述

我有两个组件需要能够读取和更改列表的上下文,但是当其中一个组件更新上下文时,另一个组件不会更新

除了上下文挂钩之外,还有更好的方法吗?如果没有,为什么它不更新,我该如何解决?

const WebsiteContext = createContext([]);

const WebsiteContextProvider = (props) => {
  const [cards, setCards] = useState([]);

  return (
    <WebsiteContext.Provider value={[cards, setCards]}>
      {props.children}
    </WebsiteContext.Provider>
  );
};

function LayersPanel(props) {
  const [cards, setCards] = useContext(WebsiteContext);
  return (
    <Box className="layersPanel">
      {cards.map((item) => (
        <h1 className="layer">{item.name}</h1>
      ))}
    </Box>
  );
}
function ControlPanel(props) {
  return (
    <div className="ControlPanel">
      <h1>hello world</h1>
      <LayersPanel></LayersPanel>
    </div>
  );
}

function WebsiteBody(props) {
  const [cards, setCards] = useContext(WebsiteContext);

  const [{ droppedItem, didDrop, isOver, canDrop }, drop] = useDrop(() => ({
    accept: "card",
    drop: () => ({
      name: "WebsiteBody",
    }),
    collect: (monitor) => ({
      droppedItem: monitor.getItem(),
      didDrop: monitor.didDrop(),
    }),
  }));
  if (didDrop) {
    const tempCardName =
      droppedItem.card.name + " " + (item_id === 0 ? "" : item_id.toString());

    const tempCard = droppedItem.card;
    tempCard.name = tempCardName;

    const temp_cards = cards;
    temp_cards.push(tempCard);

    setCards(temp_cards);

    item_id += 1;
  }

  return (
    <Box ref={drop} w="100vw" h="100vh" backgroundColor="yellow.400" display="flex">
      {cards.map((item) => item.component.code)}
    </Box>
  );
}

let item_id = 0;

function WebsiteEditor(props) {
  return (
    <ChakraProvider>
      <DndProvider backend={HTML5Backend}>
        <WebsiteContextProvider>
          <WebsiteBody></WebsiteBody>
          <ControlPanel></ControlPanel>
        </WebsiteContextProvider>
      </DndProvider>
    </ChakraProvider>
  );
}

标签: reactjsreact-hooks

解决方案


  • 您应该useMemo提供由提供商提供的任何非简单值;否则它将在每次渲染时重新计算。
  • 您不是setCards用新对象调用,而是在cards内部发生变异。使用 egsetCards([...cards, tempCard]);确保您使用的是新对象。
  • 你同样在内部改变了card被丢弃的东西。您可以制作一个浅拷贝const tempCard = {...droppedItem.card};(并且您可以在其中组合名称更改{...droppedItem.card, name: tempCardName}:)
  • 使用像你这样的全局变量item_id不是惯用的 React。考虑一个随机 ID,或者一个基于时间的 ID,或者如果您确实需要顺序 ID,它也应该是状态的一部分。
  • 您可能希望为您的上下文状态考虑useReducer而不是对。useState

推荐阅读