何时使用控制道具或状态降低器(附代码)

108 阅读2分钟

你可能已经使用了实现控制道具模式的组件或元素。比如说。

react 文档中阅读更多关于控制道具的概念。

你可能对状态减速器的概念没有什么经验。与控制道具相比,内置的 react 元素并不支持状态还原器(尽管我听说 reason-react 支持)。我的库downshift支持一个状态还原器。这里有一个使用它的例子,防止菜单在选择了一个项目后关闭:

function stateReducer(state, changes) {
  if (changes.type === Downshift.stateChangeTypes.clickItem) {
    // when the user clicks an item, prevent
    // keep the isOpen to true
    return {...changes, isOpen: true}
  }
  return changes
}
const ui = (
  
    {() => {/* some ui stuff */}}
  
)

你可以从我的Advanced React Component Patterns材料中学习如何实现这些模式。

这两种模式都可以帮助你将状态管理暴露给组件消费者,虽然它们有明显不同的API,但它们允许许多相同的功能。所以,今天我想回答一个我收到过很多次的问题,那就是。"我应该在什么时候暴露一个状态还原器还是一个控制道具?"

控制道具客观上更强大,因为它允许从组件外部对状态进行完全控制。让我们以我最喜欢的Toggle组件为例:

class Example extends React.Component {
  state = {on: false, inputValue: 'off'}
  handleToggle = on => {
    this.setState({on, inputValue: on ? 'on' : 'off'})
  }
  handleChange = ({target: {value}}) => {
    if (value === 'on') {
      this.setState({on: true})
    } else if (value === 'off') {
      this.setState({on: false})
    }
    this.setState({inputValue: value})
  }
  render() {
    const {on} = this.state
    return (
      
        {/*
          here we're using the `value` control prop
          exposed by the  component
        */}
        
        {/*
          here we're using the `on` control prop
          exposed by the  component.
        */}
        
      
    )
  }
}

下面是这个组件的渲染版本:

gif of the rendered component showing an input and toggle that sync their state

你可以看到,我可以通过改变输入组件的文本来控制切换按钮的状态,并通过点击切换按钮来控制输入的状态。这很强大,因为它使我能够完全控制这些组件的状态。

然而,控制道具也是有代价的。它们要求消费者自己完全管理状态,这意味着消费者必须有一个带有状态的类组件和变化处理程序来更新该状态。

状态还原器不需要自己管理组件的状态(尽管他们可以根据需要管理自己的一些状态)。下面是一个使用状态还原器的例子:

class Example extends React.Component {
  initialState = {timesClicked: 0}
  state = this.initialState
  handleToggle = (...args) => {
    this.setState(({timesClicked}) => ({
      timesClicked: timesClicked + 1,
    }))
  }
  handleReset = (...args) => {
    this.setState(this.initialState)
  }
  toggleStateReducer = (state, changes) => {
    if (this.state.timesClicked >= 4) {
      return {...changes, on: false}
    }
    return changes
  }
  render() {
    const {timesClicked} = this.state
    return (
      
        
        {timesClicked > 4 ? (
          
            Whoa, you clicked too much!
            
          
        ) : (
          Click count: {timesClicked}
        )}
      
    )
  }
}

这是一个渲染后的交互的gif图:

gif of the rendered component showing a toggle, reset button, and counter that's limited to 4 toggles.

现在,你完全可以用控制道具来实现这种体验,但我认为如果你能使用状态还原器,那就更简单了。状态还原器最大的限制是不可能从它的正常setState 调用之外设置组件的状态(我无法用状态还原器实现第一个例子)。

我希望这对你有帮助欢迎在这个codeandbox中查看实现和玩弄一些东西。

祝您好运!