Issue
I'd like to store a reference to a class in state but an error occurs.
Specifically, the following:
useState(SomeClass)
results in:
Class constructor SomeClass cannot be invoked without 'new'
🤔...
I can find another route for my specific need but I'd like to understand what the issue is here exactly.
--
FWIW here's a concrete situation where the above would be useful:
Consider a component that displays a list of Super[] but filtered by subclass. The component contains a set of radio buttons to set the filtering. e.g.
const FilterableListView = (props:{items:SuperType[]})=>{
const [SelectedType,setType] = useState(DefaultType as SuperType)// where DefaultType extends SuperType
const itemsToDisplay = props.items.filter(item=>item instanceof SelectedType)
// in radio button callback somewhere...
setType(SomeOtherSubType)
...
}
Here the state is the filtering criteria. No need for instances of any of the class references.
Again, I can skin this cat in many ways — I just would like to know why useState(Class) results an attempt to instantiate Class.
Solution
The reason you cannot use a class as state is because useState allows for Lazy initial state.
The
initialStateargument is the state used during the initial render. In subsequent renders, it is disregarded. If the initial state is the result of an expensive computation, you may provide a function instead, which will be executed only on the initial render:
// lazy initial state example
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
One possible solution is to wrap your class in an object, like { maker: MyClass }. Here is a minimal complete example. Click the create to create objects. Click ⚫️ or ⬛️ to change the type of object that is created.
class Circle {
constructor() { this.value = "⚫️" }
}
class Square {
constructor() { this.value = "⬛️" }
}
function App() {
const [mode, setMode] = React.useState({ maker: Circle })
const [elements, setElements] = React.useState([])
return <div>
<button
onClick={_ => setMode({ maker: Square })}
disabled={mode.maker === Square}
children="⬛️"
/>
<button
onClick={_ => setMode({ maker: Circle })}
disabled={mode.maker === Circle}
children="⚫️"
/>
<button
onClick={_ => setElements([...elements, new mode.maker()])}
children="create"
/>
{elements.map(e => <div className="element">{e.value}</div>)}
</div>
}
ReactDOM.render(<App/>, document.querySelector("#app"))
.element {
display: inline-block;
margin: 5px;
}
button[disabled] {
border-color: red;
border-radius: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Answered By - よつば
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.