有条件地使用自定义 React hooks?

问题描述 投票:0回答:1

我有两个自定义的 React 钩子,可以获取不同的数据并解析它。两个钩子都返回相同类型的对象。我有一个显示该数据的组件,并且根据“变体”道具,我希望它决定安装这两个钩子中的哪一个。

示例代码:

const useJohn = () => {
  // fetch & parse some data
  return { parsedData: { date: new Date(), name: 'John Doe' } }
}
const useJane = () => {
  // fetch & parse some data
  return { parsedData: { date: new Date(), name: 'Jane Smith' } }
}
const dataDisplay = ({ variant }: { variant: 'John' | 'Jane' }) => {
  const hook = variant === 'John' ? useJohn : useJane
  const { parsedData } = hook()
  return <div>{`${parsedData.date.toString()} ${parsedData.name}`}</div>
}

我没有从这种模式中收到任何警告/错误,一切似乎都工作正常。这是有条件地使用自定义挂钩的合法方式吗?或者这个模式有什么我不知道的问题吗?

reactjs react-hooks conditional-operator
1个回答
0
投票

好吧,首先,我们假设 useJohn 和 useJane 都在这里调用一些效果。

如果他们这样做了,就会做:

const hook = variant === 'John' ? useJohn : useJane
const { parsedData } = hook()

是错误的,并且会失败!

如果它还没有失败,那是因为你没有更新组件的 prop。但是一旦 prop 发生变化,被调用的钩子就会改变,并且你将破坏一个反应不变量,即组件应该在每次渲染时渲染完全相同数量的钩子调用。

也就是说,这会失败:

const MyComponent = () => { const [data, setData] = useState<'John' | 'Jane'>('John'); useEffect(() => { setTimeout(() => setData('Jane'), 1000) }, [setData]) <dataDisplay variant={{variant: data}} />
你应该如何解决这个问题?

要么创建一个高阶组件来处理 John 与 Jane 的决策,这样您就有两个组件:一个使用 John,另一个始终使用 Jane,并使用相同的显示组件:

const DecideJohnVsJane = (choice: 'John' | 'Jane') => { switch (choice) { case "John": return <JohnComponent /> case "Jane": return <JaneComponent /> } } const JohnComponent = () => { const parsedData = useJohn(); return <DisplayComponent data={parsedData} /> } const JaneComponent = () => { const parsedData = useJane(); return <DisplayComponent data={parsedData} /> } const DisplayComponent = (parsedData) => <div>{`${parsedData.date.toString()} ${parsedData.name}`}</div>
另一种可能更简单的方法是创建单一效果:

const useJaneOrJohn = (choice: 'John' | 'Jane') => { switch (choice) { case 'John': // fetch the john specific stuff return parsedData case 'Jane': // fetch the jane specific stuff return parsedData } }
哪个最好实际上取决于您的问题中未共享的上下文,并且该选择取决于您。

© www.soinside.com 2019 - 2024. All rights reserved.