映射数组在将本地存储放入 React Hooks useState 时出现错误渲染(一切看起来都颠倒了)* 第一次代码看起来很乱

Mapping array get error rendering when doing localstorage into React Hooks useState (everything looks upside down) * first time code looks messy

import React, { useState, useEffect } from 'react';
        import {
            FormControl,
            Form,
            Button,
            Container,
            Card,
            Row,
            Col,
        } from 'react-bootstrap';
        import { nanoid } from 'nanoid';
        import axios from 'axios';
        import * as usertz from 'user-timezone';
        import './card.css';
        import slp from '../assets/SLP.png';
        import ronin from '../assets/ronin.png';
        
        const AxieAPI = () => {
            const [toggle, setToggle] = useState(false);
            const [price, setPrice] = useState([{ current_price: '' }]);
            const [addFormData, setAddFormData] = useState({
                myName: '',
                roninAddress: '',
                manager: '',
                scholar: '',
            });
            const [dataAll, setDataAll] = useState([
                {
                    id: '',
                    myName: '',
                    roninAddress: '',
                manager: '',
                scholar: '',
                data: {
                    slp: {
                        total: '',
                        claimableTotal: '',
                        lastClaimedItemA: '',
                        todaySoFar: '',
                        yesterdaySLP: '',
                    },
                    leaderboard: {
                        winRate: '',
                        winTotal: '',
                        drawTotal: '',
                        loseTotal: '',
                        elo: '',
                        rank: '',
                        name: '',
                    },
                },
            },
        ]);
    
        const baseURL =
            'https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=smooth-love-potion&order=market_cap_desc&per_page=100&page=1&sparkline=false';
    
        // const {
        //  myName,
        //  roninAddress,
        //  manager,
        //  scholar,
        //  data: {
        //      slp: {
        //          total,
        //          claimableTotal,
        //          lastClaimedItemA,
        //          todaySoFar,
        //          yesterdaySLP,
        //      },
        //      leaderboard: { winRate, winTotal, drawTotal, loseTotal, elo, rank, name },
        //  },
        // } = dataAll;
    
        useEffect(() => {
            async function fetchData() {
                await axios.get(baseURL).then((response) => {
                    // eslint-disable-next-line
                    response.data.map((pri) => {
                        const answer = pri.current_price;
                        setPrice(answer);
                    });
                });
    
                // await localStorage.setItem('localData', JSON.stringify(dataAll));
                const newData = JSON.parse(localStorage.getItem('localData'));
                setDataAll(newData);
            }
            fetchData();
            // eslint-disable-next-line
        }, [dataAll]);
    
        const userAddress = addFormData.roninAddress.slice(6);
    
        var options = {
            method: 'GET',
            url: `https://axie-infinity.p.rapidapi.com/get-update/0x${userAddress}`,
            params: { id: `0x${userAddress}` },
            headers: {
                'x-rapidapi-host': process.env.REACT_APP_HOST,
                'x-rapidapi-key': process.env.REACT_APP_KEY,
            },
        };
    
        const onChangeHandler = async (e) => {
            // setRoninAddress(e.target.value);
            await e.preventDefault();
            try {
                const fieldName = e.target.getAttribute('name');
                const fieldValue = e.target.value;
                const newFormData = { ...addFormData };
                newFormData[fieldName] = fieldValue;
                setAddFormData(newFormData);
            } catch (error) {
                console.log(error);
            }
        };
    
        const onSubmitHandler = async (e) => {
            await e.preventDefault();
    
            await axios
                .request(options)
                .then(function (response) {
                    const newUser = {
                        id: nanoid(),
                        myName: addFormData.myName,
                        roninAddress: addFormData.roninAddress,
                        manager: addFormData.manager,
                        scholar: addFormData.scholar,
                        data: response.data,
                    };
                    const newUsers = [...dataAll, newUser];
                    setDataAll(newUsers);
                    // console.log(response.data);
                })
                .catch(function (error) {
                    console.error(error);
                });
            localStorage.setItem('localData', JSON.stringify(dataAll));
            //  localStorage.setItem('localData', JSON.stringify(dataAll));
    
            e.target.reset();
        };
    
        return (
            <div>
                <Container className="p-4">
                    <Button onClick={() => setToggle(!toggle)} className="mb-5">
                        Add Scholar
                    </Button>
                    {toggle && (
                        <Form onSubmit={onSubmitHandler}>
                            <Row className="mb-3">
                                <Form.Group as={Col} sm={12} lg={6}>
                                    <Form.Label>Scholar Name</Form.Label>
                                    <FormControl
                                        aria-label="Small"
                                        aria-describedby="inputGroup-sizing-sm"
                                        name="myName"
                                        onChange={onChangeHandler}
                                    />
                                </Form.Group>
    
                                <Form.Group as={Col} sm={12} lg={6}>
                                    <Form.Label>Ronin Address</Form.Label>
                                    <FormControl
                                        aria-label="Small"
                                        aria-describedby="inputGroup-sizing-sm"
                                        // value={roninAddress}
                                        placeholder="ronin:12345-54321"
                                        name="roninAddress"
                                        onChange={onChangeHandler}
                                    />
                                </Form.Group>
                            </Row>
                            <Row>
                                <Form.Group as={Col} sm={12} lg={6}>
                                    <Form.Label>Manager %</Form.Label>
    
                                    <FormControl
                                        aria-label="Small"
                                        aria-describedby="inputGroup-sizing-sm"
                                        name="manager"
                                        type="number"
                                        onChange={onChangeHandler}
                                    />
                                </Form.Group>
    
                                <Form.Group as={Col} sm={12} lg={6}>
                                    <Form.Label>Scholar %</Form.Label>
                                    <FormControl
                                        aria-label="Small"
                                        aria-describedby="inputGroup-sizing-sm"
                                        name="scholar"
                                        type="number"
                                        onChange={onChangeHandler}
                                    />
                                </Form.Group>
                            </Row>
    
                            <div className="d-grid gap-2 pt-3">
                                <Button type="submit" size="lg">
                                    Add User
                                </Button>
                            </div>
                        </Form>
                    )}
    
                    <Container>
                        <Row>
                            {dataAll.slice(2).map((singleData) => {
                                const myName = singleData.myName;
                                const manager = singleData.manager;
                                const scholar = singleData.scholar;
                                const roninAddress = singleData.roninAddress;
                                const totalSlp = singleData.data.slp.total;
                                const claimableTotal = singleData.data.slp.claimableTotal;
                                const lastClaimedItemAt = singleData.data.slp.lastClaimedItemAt;
                                const todaySoFar = singleData.data.slp.todaySoFar;
                                const yesterdaySLP = singleData.data.slp.yesterdaySLP;
                                // const winRate = singleData.data.leaderboard.winRate;
                                // const winTotal = singleData.data.leaderboard.winTotal;
                                // const drawTotal = singleData.data.leaderboard.drawTotal;
                                // const loseTotal = singleData.data.leaderboard.lostTotal;
                                const elo = singleData.data.leaderboard.elo;
                                const rank = singleData.data.leaderboard.rank;
                                const name = singleData.data.leaderboard.name;
    
                                const unixTimeStamp = lastClaimedItemAt;
                                const dateTimeFormat = 'MMMM Do, YYYY h:mm ss A';
                                const datetime = usertz.datetime(unixTimeStamp, dateTimeFormat);
    
                                const newUnixTimeStamp = lastClaimedItemAt + 1209600;
                                const newdatetime = usertz.datetime(
                                    newUnixTimeStamp,
                                    dateTimeFormat
                                );
    
                                const totalSlpPrice = price * totalSlp;
                                const finaltotalSlpPrice = totalSlpPrice.toFixed(2);
                                return (
                                    <Card
                                        style={{
                                            width: '22rem',
                                            backgroundColor: '#4f4f4f',
                                            padding: '20px',
                                            marginTop: '30px',
                                            marginRight: '10px',
                                        }}
                                        key={singleData.id}
                                    >
                                        <Card.Body>
                                            <Card.Title className="text-center">{name}</Card.Title>
                                            Scholar: <span className="font-weight-bold">{myName}</span>
                                            <p className="address">
                                                {' '}
                                                <img src={ronin} alt="ronin" height="20px"></img>{' '}
                                                {roninAddress}
                                            </p>
                                            <Card.Subtitle className="mb-2 text-muted"></Card.Subtitle>
                                            <Row>
                                                <Card.Text
                                                    as={Col}
                                                    className="text-center bg-secondary rounded p-2 m-1 d-flex align-items-center justify-content-center"
                                                >
                                                    <div>
                                                        In-Game SLP
                                                        <h2>
                                                            <span style={{ color: '#3cf0cb' }}>{totalSlp}</span>
                                                            <img height="35px" src={slp} alt={slp}></img>
                                                        </h2>
                                                        <p>USD {finaltotalSlpPrice}</p>
                                                    </div>
                                                </Card.Text>
                                                <Card.Text
                                                    as={Col}
                                                    className="text-center bg-secondary rounded p-2 m-1 d-flex align-items-center justify-content-center"
                                                >
                                                    <div>
                                                        Claimable SLP
                                                        <h2>
                                                            <span style={{ color: '#3cf0cb' }}>
                                                                {claimableTotal}
                                                                <img height="35px" src={slp} alt={slp}></img>
                                                            </span>
                                                        </h2>
                                                    </div>
                                                </Card.Text>
                                            </Row>
                                            Previos Claim: {datetime}
                                            <br />
                                            Next Claim: {newdatetime}
                                            <Card.Text className="bg-dark p-1">
                                                MMR ⚔️ : {elo}
                                                <br />
                                                Rank  : {rank}
                                                <br />
                                                SLP Today: {todaySoFar}
                                                <br />
                                                SLP Yesterday: {yesterdaySLP}
                                                <br />
                                            </Card.Text>
                                            <Card.Text className="p-2 bg-dark">
                                                Manager: {manager} % <br />
                                                Scholar: {scholar} %
                                            </Card.Text>
                                        </Card.Body>
                                        {/* <Button onRemove={onRemove}></Button> */}
                                    </Card>
                                );
                            })}
                        </Row>
                    </Container>
                </Container>
            </div>
        );
    };

export default AxieAPI;

第一次挑战自己编写 localstorage 代码时,我编写的代码看起来颠倒了。谁能帮我纠正这个问题?数组映射似乎关闭,因为它出错了“无法读取 null 的属性”

i 反击另一个问题,即一旦 i 运行 npm start 。它没有记录第一个数据全部进入状态意味着它没有记录一个数据 return null ==> 导致映射数组错误就像一个链。

我一直在尝试调整 localstorage 保存数据并获取数据,似乎每次刷新时数据都会被擦除。我认为数据存储的 useEffect 和 Submit 存在一些代码错误 + 每次都必须 运行 将空数据保存到本地存储中以防止数组映射错误。

import React, { useState, useEffect } from 'react';
import {
    FormControl,
    Form,
    Button,
    Container,
    Card,
    Row,
    Col,
} from 'react-bootstrap';
import { nanoid } from 'nanoid';
import axios from 'axios';
import * as usertz from 'user-timezone';
import './card.css';
import slp from '../assets/SLP.png';
import ronin from '../assets/ronin.png';
import useLocalStorage from './hooks/useLocalStorage';

const AxieAPI = () => {
    const [toggle, setToggle] = useState(false);
    const [price, setPrice] = useState([{ current_price: '' }]);
    const [addFormData, setAddFormData] = useState({
        myName: '',
        roninAddress: '',
        manager: '',
        scholar: '',
    });

    const [dataAll, setDataAll] = useLocalStorage('localData', [
        {
            id: '',
            myName: '',
            roninAddress: '',
            manager: '',
            scholar: '',
            data: {
                slp: {
                    total: '',
                    claimableTotal: '',
                    lastClaimedItemA: '',
                    todaySoFar: '',
                    yesterdaySLP: '',
                },
                leaderboard: {
                    winRate: '',
                    winTotal: '',
                    drawTotal: '',
                    loseTotal: '',
                    elo: '',
                    rank: '',
                    name: '',
                },
            },
        },
    ]);

    const baseURL =
        'https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=smooth-love-potion&order=market_cap_desc&per_page=100&page=1&sparkline=false';

    useEffect(() => {
        async function fetchData() {
            await axios.get(baseURL).then((response) => {
                // eslint-disable-next-line
                response.data.map((pri) => {
                    const answer = pri.current_price;
                    setPrice(answer);
                });
            });
            localStorage.setItem('localData', JSON.stringify(dataAll));
        }
        fetchData();
        // eslint-disable-next-line
    }, [dataAll]);

    const userAddress = addFormData.roninAddress.slice(6);

    var options = {
        method: 'GET',
        url: `https://axie-infinity.p.rapidapi.com/get-update/0x${userAddress}`,
        params: { id: `0x${userAddress}` },
        headers: {
            'x-rapidapi-host': process.env.REACT_APP_HOST,
            'x-rapidapi-key': process.env.REACT_APP_KEY,
        },
    };

const onChangeHandler = async (e) => {
    // setRoninAddress(e.target.value);
    await e.preventDefault();
    try {
        const fieldName = e.target.getAttribute('name');
        const fieldValue = e.target.value;
        const newFormData = { ...addFormData };
        newFormData[fieldName] = fieldValue;
        setAddFormData(newFormData);
    } catch (error) {
        console.log(error);
    }
};

const onSubmitHandler = async (e) => {
    await e.preventDefault();

    await axios
        .request(options)
        .then(function (response) {
            const newUser = {
                id: nanoid(),
                myName: addFormData.myName,
                roninAddress: addFormData.roninAddress,
                manager: addFormData.manager,
                scholar: addFormData.scholar,
                data: response.data,
            };
            const newUsers = [...dataAll, newUser];
            setDataAll(newUsers);
            // console.log(response.data);
            localStorage.setItem('localData', JSON.stringify(dataAll));
        })
        .catch(function (error) {
            console.error(error);
        });
    // localStorage.setItem('localData', JSON.stringify(dataAll));

    e.target.reset();
};

return (
    <div>
        <Container className="p-4">
            <Button onClick={() => setToggle(!toggle)} className="mb-5">
                Add Scholar
            </Button>
            {toggle && (
                <Form onSubmit={onSubmitHandler}>
                    <Row className="mb-3">
                        <Form.Group as={Col} sm={12} lg={6}>
                            <Form.Label>Scholar Name</Form.Label>
                            <FormControl
                                aria-label="Small"
                                aria-describedby="inputGroup-sizing-sm"
                                name="myName"
                                onChange={onChangeHandler}
                            />
                        </Form.Group>

                        <Form.Group as={Col} sm={12} lg={6}>
                            <Form.Label>Ronin Address</Form.Label>
                            <FormControl
                                aria-label="Small"
                                aria-describedby="inputGroup-sizing-sm"
                                // value={roninAddress}
                                placeholder="ronin:12345-54321"
                                name="roninAddress"
                                onChange={onChangeHandler}
                            />
                        </Form.Group>
                    </Row>
                    <Row>
                        <Form.Group as={Col} sm={12} lg={6}>
                            <Form.Label>Manager %</Form.Label>

                            <FormControl
                                aria-label="Small"
                                aria-describedby="inputGroup-sizing-sm"
                                name="manager"
                                type="number"
                                onChange={onChangeHandler}
                            />
                        </Form.Group>

                        <Form.Group as={Col} sm={12} lg={6}>
                            <Form.Label>Scholar %</Form.Label>
                            <FormControl
                                aria-label="Small"
                                aria-describedby="inputGroup-sizing-sm"
                                name="scholar"
                                type="number"
                                onChange={onChangeHandler}
                            />
                        </Form.Group>
                    </Row>

                    <div className="d-grid gap-2 pt-3">
                        <Button type="submit" size="lg">
                            Add User
                        </Button>
                    </div>
                </Form>
            )}

            <Container>
                <Row>
                    {dataAll.slice(1).map((singleData) => {
                        const myName = singleData.myName;
                        const manager = singleData.manager;
                        const scholar = singleData.scholar;
                        const roninAddress = singleData.roninAddress;
                        const totalSlp = singleData.data.slp.total;
                        const claimableTotal = singleData.data.slp.claimableTotal;
                        const lastClaimedItemAt = singleData.data.slp.lastClaimedItemAt;
                        const todaySoFar = singleData.data.slp.todaySoFar;
                        const yesterdaySLP = singleData.data.slp.yesterdaySLP;
                        // const winRate = singleData.data.leaderboard.winRate;
                        // const winTotal = singleData.data.leaderboard.winTotal;
                        // const drawTotal = singleData.data.leaderboard.drawTotal;
                        // const loseTotal = singleData.data.leaderboard.lostTotal;
                        const elo = singleData.data.leaderboard.elo;
                        const rank = singleData.data.leaderboard.rank;
                        const name = singleData.data.leaderboard.name;

                        const unixTimeStamp = lastClaimedItemAt;
                        const dateTimeFormat = 'MMMM Do, YYYY h:mm ss A';
                        const datetime = usertz.datetime(unixTimeStamp, dateTimeFormat);

                        const newUnixTimeStamp = lastClaimedItemAt + 1209600;
                        const newdatetime = usertz.datetime(
                            newUnixTimeStamp,
                            dateTimeFormat
                        );

                        const totalSlpPrice = price * totalSlp;
                        const finaltotalSlpPrice = totalSlpPrice.toFixed(2);
                        return (
                            <Card
                                style={{
                                    width: '22rem',
                                    backgroundColor: '#4f4f4f',
                                    padding: '20px',
                                    marginTop: '30px',
                                    marginRight: '10px',
                                }}
                                key={singleData.id}
                            >
                                <Card.Body>
                                    <Card.Title className="text-center">{name}</Card.Title>
                                    Scholar: <span className="font-weight-bold">{myName}</span>
                                    <p className="address">
                                        {' '}
                                        <img src={ronin} alt="ronin" height="20px"></img>{' '}
                                        {roninAddress}
                                    </p>
                                    <Card.Subtitle className="mb-2 text-muted"></Card.Subtitle>
                                    <Row>
                                        <Card.Text
                                            as={Col}
                                            className="text-center bg-secondary rounded p-2 m-1 d-flex align-items-center justify-content-center"
                                        >
                                            <div>
                                                In-Game SLP
                                                <h2>
                                                    <span style={{ color: '#3cf0cb' }}>{totalSlp}</span>
                                                    <img height="35px" src={slp} alt={slp}></img>
                                                </h2>
                                                <p>USD {finaltotalSlpPrice}</p>
                                            </div>
                                        </Card.Text>
                                        <Card.Text
                                            as={Col}
                                            className="text-center bg-secondary rounded p-2 m-1 d-flex align-items-center justify-content-center"
                                        >
                                            <div>
                                                Claimable SLP
                                                <h2>
                                                    <span style={{ color: '#3cf0cb' }}>
                                                        {claimableTotal}
                                                        <img height="35px" src={slp} alt={slp}></img>
                                                    </span>
                                                </h2>
                                            </div>
                                        </Card.Text>
                                    </Row>
                                    Previos Claim: {datetime}
                                    <br />
                                    Next Claim: {newdatetime}
                                    <Card.Text className="bg-dark p-1">
                                        MMR ⚔️ : {elo}
                                        <br />
                                        Rank  : {rank}
                                        <br />
                                        SLP Today: {todaySoFar}
                                        <br />
                                        SLP Yesterday: {yesterdaySLP}
                                        <br />
                                    </Card.Text>
                                    <Card.Text className="p-2 bg-dark">
                                        Manager: {manager} % <br />
                                        Scholar: {scholar} %
                                    </Card.Text>
                                </Card.Body>
                            </Card>
                        );
                    })}
                </Row>
            </Container>
        </Container>
    </div>
    );
};

export default AxieAPI;

我似乎设法用 localStorage 修复了它。 如果你也遇到这样的可以看看