反应 useState 选项值比 onChange 选择落后 1 步 [英] React useState option value 1 step behind onChange selection
问题描述
size.value
状态是 _updateData
函数触发 的 onChange 后的一个选项.例如,假设
的起始 defaultValue 选项为All",
locations
为空...该选项更改为Medium",locations
为All"...选项更改为Large",locations
为Medium"...等等.最初,我希望 _updateData
函数在选择了All"的情况下运行 onload 也不起作用,它会抛出错误无法读取 setSize({value: event.target.value})
.我在这里做错了什么?谢谢您的帮助.
const Map = () =>{const [viewport, setViewport] = useState({经度:-98.58,纬度:39.83,缩放:3.5})const [locations, setLocations] = useState([])const [geojson, setGeojson] = useState(null)const [size, setSize] = useState({value: "All"})useEffect(() => {设置位置(地理数据)_updateData()}, []);const _updateViewport = 视口 =>{设置视口(视口)}const _updateData = 事件 =>{setSize({value: event.target.value})const tempLocations = [];location.forEach(function(res) {if (size.value === "All") {tempLocations.push(res);} else if (res.Size === size.value) {tempLocations.push(res);}});变量数据 = {...};setGeojson(数据);}返回 (<ReactMapGL{...视口}onViewportChange={_updateViewport}宽度="100%"高度="100%"地图样式={地图样式}mapboxApiAccessToken={TOKEN}><Source id="my-data" type="geojson" data={geojson}><图层{...图标}/></来源><div style={navStyle}><NavigationControl onViewportChange={_updateViewport}/><select onChange={_updateData} defaultValue={size}><option value="All">All</option><option value="Large">Large</option><option value="Medium">Medium</option><option value="Small">Small</option><option value="Very Small">Very Small</option></选择>
</ReactMapGL>);}导出默认地图;
是的,您正在挂载 useEffect
钩子中调用 select 的 onChange
处理程序,而没有事件对象取消引用 target
属性.我会分解出 updateData
代码的其余部分,以便您可以使用初始状态值调用它.这将允许您使用初始大小状态日期更新安装位置详细信息和选择的 onChange
将保持原样.>
注意:您应该注意状态更新要到下一个渲染周期才会生效,因此在您的代码中,您使用新值调用 setSize
但继续处理定位当前大小值,所以需要转发当前值.
const Map = () =>{const [viewport, setViewport] = useState({经度:-98.58,纬度:39.83,缩放:3.5})const [locations, setLocations] = useState([])const [geojson, setGeojson] = useState(null)const [size, setSize] = useState({value: "All"})//这里的初始大小状态useEffect(() => {设置位置(地理数据);更新位置数据(大小.值);//使用初始大小状态值在 mount 上调用位置更新器}, []);const _updateViewport = 视口 =>{设置视口(视口)}const _updateData = 事件 =>{setSize({value: event.target.value})updateLocationData(event.target.value);//转发当前大小值}const updateLocationData = (sizeValue) =>{//转发大小值const tempLocations = [];location.forEach(function(res) {if (sizeValue === "All") {//转发大小值进行比较tempLocations.push(res);} else if (res.Size === sizeValue) {//转发大小值进行比较tempLocations.push(res);}});变量数据 = {...};setGeojson(数据);};返回 (<ReactMapGL{...视口}onViewportChange={_updateViewport}宽度=100%"高度=100%"地图样式={地图样式}mapboxApiAccessToken={TOKEN}><Source id="my-data";类型=geojson";数据={geojson}><图层{...icon}/></来源><div style={navStyle}><NavigationControl onViewportChange={_updateViewport}/><select onChange={_updateData} defaultValue={size.value}>//需要解包实际大小值<option value=All">All</option><option value=Large">Large</option><option value=Medium">Medium</option><option value=Small">Small</option><选项值=非常小">非常小</option></选择>
</ReactMapGL>);}导出默认地图;
The size.value
state is one option behind when the _updateData
function triggers onChange of the <select>
. For example, Let's say the starting defaultValue option of <select>
is "All", locations
is empty...the option is changed to "Medium", locations
is "All"...the option is changed to "Large", locations
is "Medium"...and so on. Initially I want the _updateData
function to run onload with "All" selected which is not working either, it throws the error Cannot read property 'target' of undefined on setSize({value: event.target.value})
. What am I doing wrong here? Thanks for the help.
const Map = () => {
const [viewport, setViewport] = useState({longitude: -98.58, latitude: 39.83, zoom: 3.5})
const [locations, setLocations] = useState([])
const [geojson, setGeojson] = useState(null)
const [size, setSize] = useState({value: "All"})
useEffect(() => {
setLocations(geodata)
_updateData()
}, []);
const _updateViewport = viewport => {
setViewport(viewport)
}
const _updateData = event => {
setSize({value: event.target.value})
const tempLocations = [];
locations.forEach(function(res) {
if (size.value === "All") {
tempLocations.push(res);
} else if (res.Size === size.value) {
tempLocations.push(res);
}
});
var data = {
...
};
setGeojson(data);
}
return (
<ReactMapGL
{...viewport}
onViewportChange={_updateViewport}
width="100%"
height="100%"
mapStyle={mapStyle}
mapboxApiAccessToken={TOKEN}>
<Source id="my-data" type="geojson" data={geojson}>
<Layer {...icon} />
</Source>
<div style={navStyle}>
<NavigationControl onViewportChange={_updateViewport} />
<select onChange={_updateData} defaultValue={size}>
<option value="All">All</option>
<option value="Large">Large</option>
<option value="Medium">Medium</option>
<option value="Small">Small</option>
<option value="Very Small">Very Small</option>
</select>
</div>
</ReactMapGL>
);
}
export default Map;
Yes, you are calling your select's onChange
handler in the mounting useEffect
hook with no event object to dereference a target
property. I would factor out the rest of the updateData
code so you can call it with the initial state value. This will allow you to update location details on mount using the initial size state date AND the select's onChange
will remain as it was previously.
NOTE: You should note that updates to state won't take effect until the next render cycle, so in your code you call setSize
with the new value but continue processing locations the current size value, so you need to forward the current value.
const Map = () => {
const [viewport, setViewport] = useState({longitude: -98.58, latitude: 39.83, zoom: 3.5})
const [locations, setLocations] = useState([])
const [geojson, setGeojson] = useState(null)
const [size, setSize] = useState({value: "All"}) // initial size state here
useEffect(() => {
setLocations(geodata);
updateLocationData(size.value); // call the location updater on mount with the initial size state value
}, []);
const _updateViewport = viewport => {
setViewport(viewport)
}
const _updateData = event => {
setSize({value: event.target.value})
updateLocationData(event.target.value); // forward current size value
}
const updateLocationData = (sizeValue) => { // forwarded size value
const tempLocations = [];
locations.forEach(function(res) {
if (sizeValue === "All") { // forwarded size value for comparison
tempLocations.push(res);
} else if (res.Size === sizeValue) { // forwarded size value for comparison
tempLocations.push(res);
}
});
var data = {
...
};
setGeojson(data);
};
return (
<ReactMapGL
{...viewport}
onViewportChange={_updateViewport}
width="100%"
height="100%"
mapStyle={mapStyle}
mapboxApiAccessToken={TOKEN}>
<Source id="my-data" type="geojson" data={geojson}>
<Layer {...icon} />
</Source>
<div style={navStyle}>
<NavigationControl onViewportChange={_updateViewport} />
<select onChange={_updateData} defaultValue={size.value}> // need to unpack the actual size value
<option value="All">All</option>
<option value="Large">Large</option>
<option value="Medium">Medium</option>
<option value="Small">Small</option>
<option value="Very Small">Very Small</option>
</select>
</div>
</ReactMapGL>
);
}
export default Map;
这篇关于反应 useState 选项值比 onChange 选择落后 1 步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!