IMO,React Hooks useState非常适合用于模式,以使用props的值或使用自己的状态来进行可选,但是当我有条件地使用hook时,皮棉显示了一些错误。
我试图使用具有以下条件但具有eslint错误React hook useState is called conditionally
的钩子。根据{{3}},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>
);
}
如何使用钩子实现与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>
);
}
}
或者在一个组件中这种props / state可选方式是错误的?
我从React JSX "defaultValue"
组件中学到了"value"
,"onChange"
,<input>
API命名和思想。
答案 0 :(得分:3)
您可以将组件分为完全受控和完全不受控制的两个部分。 Demo
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} />
);
};
答案 1 :(得分:0)
好问题!我认为,可以通过使useState
成为无条件调用,而仅使零件成为条件,从而决定要呈现的状态和使用的更改处理程序,从而通过钩子来解决。
我刚刚发布了一个可以解决此问题的钩子:use-optionally-controlled-state
用法:
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} />
组件,其中两个道具都可以有选择地控制)。