【问题标题】:handle useReducer if pass from props如果从 props 传递,则处理 useReducer
【发布时间】:2021-04-09 10:01:23
【问题描述】:

我正在尝试在特定用例的组件中覆盖 useReducer

按照我的overfly简化工作状态:

function defaultToggleReducer (state, action) {
  console.log('Default toggler used')
  return !state
}

function customTogglerReducer (state, action) {
  console.log('Custom toggler used')
  return !state
}

// Dummy wrap to log the initialization from `Togller` component to point the twice initializations
function toggleInitializer (state) {
  console.log('toggleInitializer')
  return state
}

function Toggler (props) {
  const [
    toggleState,
    toggleDispatch,
  ] = React.useReducer(defaultToggleReducer, false, toggleInitializer)
  
  // Here is the prt making the previous `useReducer` useless
  const state = props.toggleState !== undefined ? props.toggleState : toggleState
  const dispatch = props.toggleDispatch || toggleDispatch
  
  return (
    <button
      type="button"
      onClick={() => dispatch({ type: 'add' })}>
      {Boolean(state).toString()}
    </button>
  )
}

function App () {
  const [customToggleState, customToggleDispatch] = React.useReducer(
    customTogglerReducer,
    false
  )

  return (
    <div>
      <fieldset>
        <legend>Default</legend>
        <Toggler />
      </fieldset>
      <fieldset>
        <legend>Customized</legend>
        <Toggler
          toggleState={customToggleState}
          toggleDispatch={customToggleDispatch} />
        <button
          type="button"
          onClick={() => customToggleDispatch({ type: 'parentAction' })}>
          This is why I want dispatch
        </button>
      </fieldset>
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root" />

在这里,有些东西闻起来很糟糕,我毫不怀疑这是有效的,但即使没有使用,useReducerToggler 中被调用的事实也让我怀疑。所以,我认为这是一个死减速器。

所以我的问题是:

您是否有办法从父组件正确实现reduce 控件(至少:比这更好)?

【问题讨论】:

    标签: reactjs react-hooks composition use-reducer


    【解决方案1】:

    使用组件的组合来解决这个问题。将 Toggler 分解为两个组件 - 愚蠢的 Toggler 需要外部减速器,DefaultToggler 渲染 Toggler,并提供减速器。

    如果您需要标准切换器,请使用DefaultToggler,如果您需要自定义版本,请使用哑Toggler,并提供自定义减速器。

    function defaultToggleReducer (state, action) {
      console.log('Default toggler used')
      return !state
    }
    
    function customTogglerReducer (state, action) {
      console.log('Custom toggler used')
      return !state
    }
    
    // Dummy wrap to log the initialization from `Togller` component to point the twice initializations
    function toggleInitializer (state) {
      console.log('toggleInitializer')
      return state
    }
    
    function Toggler ({ toggleState: state, toggleDispatch: dispatch }) {  
      return (
        <button
          type="button"
          onClick={() => dispatch({ type: 'add' })}>
          {Boolean(state).toString()}
        </button>
      )
    }
    
    function DefaultToggler () {
      const [
        toggleState,
        toggleDispatch,
      ] = React.useReducer(defaultToggleReducer, false, toggleInitializer)
    
      return (
        <Toggler 
          toggleState={toggleState} 
          toggleDispatch={toggleDispatch} 
          />
      );
    };
    
    function App () {
      const [customToggleState, customToggleDispatch] = React.useReducer(
        customTogglerReducer,
        false
      )
    
      return (
        <div>
          <fieldset>
            <legend>Default</legend>
            <DefaultToggler />
          </fieldset>
          <fieldset>
            <legend>Customized</legend>
            <Toggler
              toggleState={customToggleState}
              toggleDispatch={customToggleDispatch} />
            <button
              type="button"
              onClick={() => customToggleDispatch({ type: 'parentAction' })}>
              This is why I want dispatch
            </button>
          </fieldset>
        </div>
      )
    }
    
    ReactDOM.render(<App />, document.getElementById('root'))
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    
    <div id="root" />

    【讨论】:

    • 哦,是的,这是有道理的!我正在考虑在复杂的上下文中换行,然后使用 Consumer blabla ...但它像这样更简单。谢谢!
    • 不客气。如果将某些功能作为组件的一部分包含在内,会使使用复杂化,请将功能提取到另一个组件或自定义挂钩,然后使用组合。上下文通常作为一种依赖注入很好,并且可以避免向下钻取,这不是这里的情况。
    • 是的,这就是为什么我没有以这种方式进行过多调查的原因。注意:组合是(并且仍然)在关键字中我确定类似的东西,这正是我要寻找的:) 仅供参考:我的最终作品包括带有变体组件的ToggleBuilder(当然它不是切换组件,而是更多具有疯狂设计功能的手风琴)再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2022-07-14
    • 2015-11-19
    • 2019-07-02
    相关资源
    最近更新 更多