react useState 选项值比 onChange 选择落后 1 步

IT技术 reactjs react-hooks react-state react-map-gl
2021-05-03 16:28:07

size.value状态是当后面一个选项_updateData功能触发平变化的<select>例如,假设起始 defaultValue 选项<select>为“All”,locations为空...该选项更改为“Medium”,locations为“All”...该选项更改为“Large”,locations为“Medium”。 ..等等。最初我希望该_updateData函数在选择了“All”的情况下运行 onload 也不起作用,它抛出错误无法读取 undefined on 的属性 'target' setSize({value: event.target.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"})

    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;
2个回答

是的,您onChangeuseEffect没有事件对象的挂载钩子中调用选择的处理程序来取消引用target属性。我会分解出其余的updateData代码,以便您可以使用初始状态值调用它。这将允许您使用初始大小状态日期更新安装位置详细信息并且选择的onChange将保持以前的状态。

注意:您应该注意状态更新直到下一个渲染周期才会生效,因此在您的代码中您setSize使用新值调用但继续处理当前大小值的位置,因此您需要转发当前值。

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 函数是异步的。因此需要一些时间来更新。请参阅useState 是否同步?. 其次,在组件挂载时调用 useEffect 函数。所以还没有发生 onchange 事件。一旦您更改了 select 标签中的选项,就会发生 Onchange 事件。只需从 useEffect 函数中删除 _updateData 即可。