如何通过react useState和useContext模拟消息/事件?

时间:2020-05-14 19:19:10

标签: javascript reactjs typescript react-hooks

我正在使用useState和useContext创建用于状态管理的React应用。到目前为止,这就像一个魅力,但现在我遇到了一个功能,该功能需要类似事件的内容:

比方说,有一个ContentPage可以渲染很多内容。用户可以滚动浏览并阅读内容。
还有一个BookmarkPage。单击书签将打开ContentPage并滚动到相应的内容。

此滚动到内容是一次性动作。理想情况下,我想在ContentPage中有一个使用ScrollTo(item)事件的事件监听器。但是反应几乎阻止了所有事件的使用。 DOM事件无法捕获到虚拟dom中,并且无法创建自定义的合成事件。
此外,“打开内容XYZ”命令可以来自组件树中的许多部分(该示例并不完全适合我要实现的内容)。只会使树冒泡的事件并不能解决问题。

所以我想反应的方法是以某种方式用应用程序状态表示此事件?

我有一个解决方法,但是它很笨拙并且有问题(这就是为什么我要发布此问题的原因):

export interface MessageQueue{
  messages: number[],
  push:(num: number)=>void,
  pop:()=>number
}

const defaultMessageQueue{
  messages:[],
  push: (num:number) => {throw new Error("don't use default");},
  pop: () => {throw new Error("don't use default");}
}

export const MessageQueueContext = React.createContext<MessageQueue>(defaultMessageQueue);

在组件中,我为此提供了

const [messages, setmessages] = useState<number[]>([]);
//...
<MessageQueueContext.Provider value={{
  messages: messages,
  push:(num:number)=>{
    setmessages([...messages, num]);
  },
  pop:()=>{
    if(messages.length==0)return;

    const message = messages[-1];
    setmessages([...messages.slice(0, -1)]);
    return message;
  }
}}>

现在,任何需要发送或接收消息的组件都可以使用上下文。
推送消息按预期工作。上下文发生更改,并且使用它的所有组件都重新呈现。
但是弹出一条消息也会更改上下文并导致重新渲染。因为没有理由这样做,所以第二次重新渲染被浪费了。

在使用useState和useContext进行状态管理的代码库中,是否存在一种干净的方法来实现动作/消息/事件?

2 个答案:

答案 0 :(得分:1)

由于您在Ionic的router(响应路由器)中使用路由,并且在两个页面之间导航,因此可以使用URL将参数传递给页面:

定义路由以使其具有可选的路径参数。像content-page/:section?

在ContentPage中,使用React Router的section获取参数(useParams)。使用useEffect创建一个section作为唯一更改的依赖项。在第一次渲染(或如果section更改)时,将调用滚动代码。

const { section } = useParams();

useEffect(() => {
  // the code to jump to the section
}, [section]);

答案 1 :(得分:0)

我不确定为什么不能将document.dispatchEvent(new CustomEvent())与关联的eventListener一起使用。 另外,如果是滚动问题,则可以使用refs