In React, you should only access an event argument inside a synchronous handler. If you do something asynchronous - like provide a state setter callback - and then try to access the event inside the callback, it won't work properly, and you won't be able to access the .value
. One possible warning you'll see is:
Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property target
on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist(). See https:// fb.me/react-event-pooling for more information.
in Container
While you can extract the value first, so you don't access the event:
const Board = ({ size }) => <div>Brush size: {size}</div>
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {brushSize: 2};
this.brushSizeChange = this.brushSizeChange.bind(this);
}
brushSizeChange(e) {
const { value } = e.target;
this.setState((prev) => { return { brushSize: value } });
}
render() {
return (
<div className="container">
<label>Brush size: </label>
<input type="range" min="1" max="10" value={this.state.brushSize} onChange={this.brushSizeChange} />
<h1>placeholder</h1>
<div className="board-container">
</div>
</div>
)
}
}
ReactDOM.render(<Container />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>
There's no need for the callback at all because you aren't setting any other state on input change.
const Board = ({ size }) => <div>Brush size: {size}</div>
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {brushSize: 2};
this.brushSizeChange = this.brushSizeChange.bind(this);
}
brushSizeChange(e) {
const { value } = e.target;
this.setState({ brushSize: value });
}
render() {
return (
<div className="container">
<label>Brush size: </label>
<input type="range" min="1" max="10" value={this.state.brushSize} onChange={this.brushSizeChange} />
<h1>placeholder</h1>
<div className="board-container">
</div>
</div>
)
}
}
ReactDOM.render(<Container />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>
Then you can pass down this.state.brushSize
to the <input>
and to the <Board>
, and they'll see and respond to the state now that it's being changed properly. (If you want the Board to see the value, you should almost certainly be doing something like <Board size={this.state.brushSize} />
- if you don't pass the state down, Board won't be able to see it)