【问题标题】:Async is driving me mad异步让我发疯
【发布时间】:2021-04-20 21:10:55
【问题描述】:

我希望我的程序在尝试渲染任何内容之前运行使用效果。计划是使用getTable()函数获取数据,然后将数据存储在redux中,然后将当前的js文件再分解一些,以便能够访问我所有类中的数据。

所以这是它调用 createMap 函数 4 或 5 次的问题,最重要的是,它是在程序有机会将数据添加到 redux 存储并有适当的数据供 createMap 函数运行之前执行此操作。

import react, { useEffect, useState } from 'react'
import axios from 'axios';
import { makeStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TablePagination from '@material-ui/core/TablePagination';
import TableRow from '@material-ui/core/TableRow';
import dom from 'react-dom'
import L from "leaflet";
//import MarkerCluster from "./Markers"
import '../../node_modules/leaflet/dist/leaflet.css'
import '../../node_modules/react-leaflet-markercluster/dist/styles.min.css'
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'
import MarkerClusterGroup from 'react-leaflet-markercluster';
import './CSS/Pmap.css'
import { useSelector, useDispatch } from "react-redux";

function Pmap() {
    const state = useSelector((state) => state)
    const dispatch = useDispatch();
    console.log(state)
    const [data, setData] = useState();
    const [rows, setRows] = useState([]);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        console.log('use effect')
        getTable();

    }, [])

    const storeData = (data) => {
        console.log(`store data called ${data.rows}`)
        dispatch({
            type: "addData",
            payload: { rows: data.rows, rowCount: data.rowCount }
        })
        console.log(`store data finished` + state)
    }

    const getTable =  () => {
        try {
            const response = axios.post("/api/get/1919")
            storeData(response.data);
            setLoading(false);
            setData(response.data)
            setRows(response.data.rows)



        } catch (err) {
            console.log(err);
        }


    }

    //********************************************* Map ************************************ */
    const customMarker = new L.Icon({
        iconUrl: "https://unpkg.com/leaflet@1.5.1/dist/images/marker-icon.png",
        iconSize: [25, 41],
        iconAnchor: [10, 41],
        popupAnchor: [2, -40]
    });


    function createMap() {
        console.log("map function called for");

        return (
            <div>
                <MapContainer center={[43.458, -80.503]} zoom={12} scrollWheelZoom={true} className='markercluster-map'>
                    <TileLayer
                        attribution='&copy; <a href="&copy; <a href="https://stadiamaps.com/">Stadia Maps</a>, &copy; <a href="https://openmaptiles.org/">OpenMapTiles</a> &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributorshttp://osm.org/copyright">OpenStreetMap</a> contributors'
                        url="https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png"
                    />
                    <MarkerClusterGroup>
                        {console.log(`state.rows : ${state}`)}
                        {
                            state.rows.map((element) => {
                                return (
                                    <Marker
                                        position={[element.Lat, element.Long]}
                                        icon={customMarker}
                                        key={element.OID} />
                                )

                            })
                        }

                    </MarkerClusterGroup>
                </MapContainer>
            </div>
        )



    }
    /**********************************************End of Map ******************************* */
    // ********************************************TABLE************************************
    const columns = [
        { id: 'last_name', label: 'Last Name', minWidth: 170 },
        { id: 'first_name', label: 'First Name', minWidth: 100 },
        { id: 'edited_occ', label: 'Occupation', minWidth: 170 },
        { id: 'Chgd_add', label: 'Address', minWidth: 170 }
    ];


    const useStyles = makeStyles({
        root: {
            width: '100%',
        },
        container: {
            maxHeight: 440,
        },
    });

    function StickyHeadTable() {
        console.log("Sticky Head Table Called")
        const classes = useStyles();
        const [page, setPage] = useState(0);
        const [rowsPerPage, setRowsPerPage] = useState(10);

        const handleChangePage = (event, newPage) => {
            setPage(newPage);
        };

        const handleChangeRowsPerPage = (event) => {
            setRowsPerPage(+event.target.value);
            setPage(0);
        };

        return (
            <Paper className={classes.root}>
                <TableContainer className={classes.container}>
                    <Table stickyHeader aria-label="sticky table">
                        <TableHead>
                            <TableRow>
                                {columns.map((column) => (
                                    <TableCell
                                        key={column.id}
                                        align={column.align}
                                        style={{ minWidth: column.minWidth }}
                                    >
                                        {column.label}
                                    </TableCell>
                                ))}
                            </TableRow>
                        </TableHead>
                        <TableBody>
                            {rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row) => {
                                return (
                                    <TableRow hover role="checkbox" tabIndex={-1} key={row.code}>
                                        {columns.map((column) => {
                                            const value = row[column.id];
                                            return (
                                                <TableCell key={column.id} align={column.align}>
                                                    {column.format && typeof value === 'number' ? column.format(value) : value}
                                                </TableCell>
                                            );
                                        })}
                                    </TableRow>
                                );
                            })}
                        </TableBody>
                    </Table>
                </TableContainer>
                <TablePagination
                    rowsPerPageOptions={[10, 25, 100]}
                    component="div"
                    count={rows.length}
                    rowsPerPage={rowsPerPage}
                    page={page}
                    onChangePage={handleChangePage}
                    onChangeRowsPerPage={handleChangeRowsPerPage}
                />
            </Paper>
        );
    }


    // ******************************************* End of table *********************************




    return (
        <div className="Pmap">


            <div>
                {createMap()}
            </div>
            <div>
                {StickyHeadTable()}
            </div>
            {console.log(`state.rows end :  ${JSON.stringify(state)}`)}

        </div>
    )
} export default Pmap; 

这是控制台日志,所有这些都在 useEffect 之前运行,我认为应该在其他任何东西有机会运行之前先运行它。我还检查了它最终是否会在需要之前将数据添加到 redux。

【问题讨论】:

  • useEffect 在每次完成渲染之后运行,而不是之前。
  • axios.post("/api/get/1919") 返回一个 Promise,它没有 data 属性,因此 state.rows 可能在随后的渲染周期中未定义(IDK,也可能是您的状态/减速器/选择器不正确)。你的意思是让getTableasyncawait回复?或者您可能打算使用 Promise 链?

标签: reactjs asynchronous redux react-redux use-effect


【解决方案1】:

useEffects 运行的最早时刻是在第一次渲染之后。 即使它之前运行过:获取是一个异步操作,因此在某些时候您的应用程序将呈现并且数据获取可能会比这晚得多。

您需要渲染一个“加载”指示器,然后在加载完成后渲染实际内容。此外,您真的不想跳过或延迟渲染类似的东西。在连接不良的情况下,加载可能需要几秒钟到几分钟的时间。你不希望人们认为你的应用程序崩溃了,因为它还没有渲染任何东西。

所以{createMap()} 变成了{loading ? "please wait, loading" : createMap()}

【讨论】:

    猜你喜欢
    • 2011-05-30
    • 2012-11-02
    • 2020-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-16
    • 2012-03-14
    相关资源
    最近更新 更多