首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >带有条件反应钩的可选受控/无控制反应部件

带有条件反应钩的可选受控/无控制反应部件
EN

Stack Overflow用户
提问于 2019-04-17 14:46:06
回答 2查看 2.9K关注 0票数 5

IMO,React是一种非常适合于从道具中选择使用值或使用自己状态的模式,但是当我有条件地使用钩子时,棉线出现了一些错误。

工作实例

我试着使用钩子,条件如下,但使用的是eslint错误React hook useState is called conditionally。根据这个医生的解释React relies on the order in which Hooks are called

代码语言:javascript
运行
复制
const Counter = ({ value, onChange, defaultValue = 0 }) => {
  const [count, onCountChange] =
    typeof value === "undefined" ? useState(defaultValue) : [value, onChange];
  return (
    <div>
      {count.toString()}
      <button
        onClick={() => {
          onCountChange(count + 1);
        }}
      >
        +
      </button>
    </div>
  );
};
function App() {
  const [count, onCountChange] = useState(0);
  return (
    <div className="App">
      <div>
        Uncontrolled Counter
        <Counter />
      </div>
      <div>
        Controlled Counter
        <Counter value={count} onChange={onCountChange} />
      </div>
    </div>
  );
}

如何使用钩子来实现与下面类组件相同的功能?

代码语言:javascript
运行
复制
class CounterClass extends React.Component {
  state = {
    value: this.props.defaultValue || 0
  };
  render() {
    const isControlled = typeof this.props.defaultValue === "undefined";
    const count = isControlled ? this.props.value : this.state.value;

    return (
      <div>
        {count.toString()}
        <button
          onClick={() => {
            isControlled &&
              this.props.onChange &&
              this.props.onChange(this.props.value + 1);
            !isControlled && this.setState({ value: this.state.value + 1 });
          }}
        >
          +
        </button>
      </div>
    );
  }
}

或者这种道具/状态在一个组件中的可选方式是错误的?

我学习了"defaultValue""value""onChange" API的命名以及从React <input>组件中学到的思想。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-17 15:06:38

您可以将组件拆分为完全控制和完全不受控制的组件。演示

代码语言:javascript
运行
复制
const CounterRepresentation = ({ value, onChange }) => (
  <div>
    {value.toString()}
    <button
      onClick={() => {
        onChange(value + 1);
      }}
    >
      +
    </button>
  </div>
);

const Uncontrolled = ({ defaultValue = 0 }) => {
  const [value, onChange] = useState(defaultValue);
  return <CounterRepresentation value={value} onChange={onChange} />;
};

// Either use representation directly or uncontrolled
const Counter = ({ value, onChange, defaultValue = 0 }) => {
  return typeof value === "undefined" ? (
    <Uncontrolled defaultValue={defaultValue} />
  ) : (
    <CounterRepresentation value={value} onChange={onChange} />
  );
};
票数 7
EN

Stack Overflow用户

发布于 2020-11-16 16:04:57

问得好!我认为可以用钩子来解决这个问题,方法是使useState调用是无条件的,并且只有在决定呈现哪种状态和使用什么更改处理程序的情况下,才能使该部分具有条件。

我刚刚发布了一个解决这个问题的钩子:使用-可选控制状态

使用:

代码语言:javascript
运行
复制
import useOptionallyControlledState from 'use-optionally-controlled-state';
 
function Expander({
  expanded: controlledExpanded,
  initialExpanded = false,
  onChange
}) {
  const [expanded, setExpanded] = useOptionallyControlledState({
    controlledValue: controlledExpanded,
    initialValue: initialExpanded,
    onChange
  });
 
  function onToggle() {
    setExpanded(!expanded);
  }
 
  return (
    <>
      <button onClick={onToggle} type="button">
        Toggle
      </button>
      {expanded && <div>{children}</div>}
    </>
  );
}

// Usage of the component:

// Controlled
<Expander expanded={expanded} onChange={onExpandedChange} />
 
// Uncontrolled using the default value for the `initialExpanded` prop
<Expander />
 
// Uncontrolled, but with a change handler if the owner wants to be notified
<Expander initialExpanded onChange={onExpandedChange} />

通过使用钩子来实现这一点,您不需要包装额外的组件,理论上您可以将它应用到同一组件中的多个道具(例如,一个<Prompt isOpen={isOpen} inputValue={inputValue} />组件,其中两个道具都是可选控制的)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55730352

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档