可选的带条件React钩的受控/非受控React组件

Jas*_*ieh 2 reactjs react-hooks

IMO,React Hooks useState非常适合将模式从props值或使用自己的状态转换为可选模式,但是当我有条件地使用hook时,皮棉显示了一些错误。

工作实例

我试图使用具有以下条件但具有eslint错误的钩子React hook useState is called conditionally。根据doc的解释React relies on the order in which Hooks are called

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>
  );
}
Run Code Online (Sandbox Code Playgroud)

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

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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

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

我了解到"defaultValue""value""onChange"从阵营JSX API命名和思想<input>的组成部分。

Yur*_*nko 5

您可以将组件分为完全受控和完全不受控制的两个部分。演示版

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} />
  );
};
Run Code Online (Sandbox Code Playgroud)