【问题标题】:React useState option value 1 step behind onChange selection反应 useState 选项值落后 onChange 选择 1 步
【发布时间】:2020-01-01 07:17:47
【问题描述】:

size.value 状态是当_updateData 函数触发<select> 的onChange 时的一个选项。例如,假设<select>的起始defaultValue选项为“All”,locations为空...选项更改为“Medium”,locations为“All”...选项更改为“大”,locations 是“中”......等等。最初,我希望_updateData 函数在选择“全部”的情况下运行 onload,这也不起作用,它会引发错误无法读取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;

【问题讨论】:

    标签: reactjs react-hooks react-state react-map-gl


    【解决方案1】:

    是的,您在挂载useEffect 钩子中调用您选择的onChange 处理程序,没有事件对象来取消引用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;
    

    【讨论】:

    • 这似乎消除了初始组件安装错误,但它似乎仍然落后了 1 步,在组件安装上也是如此。所以位置是空的[],然后与之前选择的数据选项一起存储;如果我在 updateLocationData 中设置一个常量,例如 const currentSize = event.target.value;那么选择时状态是正确的,但是初始加载不起作用,因为它是未定义的
    • @ckingchris 对不起,我明白你现在的意思了,用修复更新了我的答案,用解释更新了 cmets。希望现在更清楚了。仅供参考,直接存储大小值而不是嵌套在对象中也会更简洁。
    • 假设
    • 别担心,我们很接近! updateLocationData 现在工作得很好:) 似乎 useEffect updateLocationData(size.value) 仍然在加载时将位置留空
    • 效果挂钩中的geoData是什么?我没有看到它在哪里定义。除了初始值之外,钩子是我看到locations 被更新的唯一地方。
    【解决方案2】:

    首先,useState 函数是异步的。因此需要一些时间来更新。见Is useState synchronous?。 其次,在组件挂载时调用 useEffect 函数。所以还没有发生 onchange 事件。一旦您更改了选择标签中的选项,就会发生 Onchange 事件。 只需从您的 useEffect 函数中删除 _updateData。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-30
      • 2019-05-25
      • 1970-01-01
      • 2021-05-26
      • 1970-01-01
      • 1970-01-01
      • 2021-05-30
      相关资源
      最近更新 更多