React useParams未定义,用于编辑用户个人资料

时间:2020-05-16 20:26:23

标签: reactjs react-router fetch react-hooks react-router-dom

看过其他有关params的帖子,但我没有运气。

我有一个用户个人资料,单击该个人资料可显示用户的元数据,并具有一个用于更改昵称键值的编辑按钮。

我的useParams昵称未定义回来。

我知道这是很多代码,我在这台计算机上坐了太长时间了,现在无法弄清楚。

我的Profile / index.js

import { Link, useParams } from 'react-router-dom';
import PropTypes from 'prop-types';

const ProfileInfo = ({ label, value }) => {
    if (typeof value === 'object')
        value = (
            <ul>
                {Object.keys(value).map((key) => {
                    return (
                        <ProfileInfo key={key} label={key} value={value[key]} />
                    );
                })}
            </ul>
        );
    else value = value.toString();
    return (
        <li>
            <strong>{label}</strong>: <span>{value}</span>
        </li>
    );
};

ProfileInfo.propTypes = {
    label: PropTypes.string,
    value: PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number,
        PropTypes.bool,
        PropTypes.object
    ])
};

const Profile = () => {
    const { nickname } = useParams()
    const [user, setUser] = useState({nickname: "Not Sure"});
    const [isLoading, setLoading] = useState (true);

    useEffect(() => {
        const abortController = new AbortController();
        const getUser = async () => {
            const url = `/profile/${nickname}`
            const res = await fetch(url, {
                method: 'GET',
                headers: { Accept: 'application/json' },
                signal: abortController.signal
            });
            if (res.ok && !abortController.signal.aborted) {
                const data = await res.json();
                setUser(data);
                setLoading(false);
            }
        };
        getUser();
        return function cleanup() {
            abortController.abort();
        };
    }, [nickname]);

    return isLoading ? (
        'Loading...'
    ) :  (
        <>
            <h2>Profile</h2>
            <ul>
                {Object.keys(user).map((key) => {
                    return (
                        <ProfileInfo key={key} label={key} value={user[key]} />
                    );
                })}
            </ul>
            <Link to={`/edit-user/${nickname}`}>Edit</Link>
        </>
    );
};

export default Profile;

我的ProfileForm / index.js

import React, { useRef, useEffect, useState } from 'react';
import { useParams, useHistory } from 'react-router-dom';

const ProfileForm = () => {
    const form = useRef(null);
    const { nickname } = useParams();
    const history = useHistory();
    const [user, setUser] = useState({});

    const handleChange = (event) => {
        if (event.target.value.trim() === '') return;
        setUser({
            ...user,
            [event.target.name]: event.target.value
        });
    };

    const save = async (event) => {
        event.preventDefault && event.preventDefault();
        event.stopPropagation && event.stopPropagation();
        console.log("save: " + user.nickname);
        const method = user.nickname ? 'PUT' : 'POST';
        const url = user.nickname ? `/profile/${nickname}` : '/profile';

        const abortController = new AbortController();
        const res = await fetch(url, {
            method,
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(user),
            signal: abortController.signal
        });
        if (res.ok && !abortController.signal.aborted) {
            const result = await res.json();
            history.push(`/edit-user/${result.nickname}`);
        }
    };

    useEffect(() => {
        form.current.reset();
        if (nickname) {
            const abortController = new AbortController();
            const getUser = async () => {
                const url = `/profile/${nickname}`;
                const res = await fetch(url, {
                    method: 'GET',
                    headers: { Accept: 'application/json' },
                    signal: abortController.signal
                });
                if (res.ok && !abortController.signal.aborted) {
                    const result = await res.json();
                    setUser(result);
                }
            };

            getUser();
            return function cleanup() {
                abortController.abort();
            };
        }
    }, [nickname]);

    return (
        <form onSubmit={save} ref={form}>
            <div>
                <label>
                    Display Name
                    <br />
                    <input
                        name={'title'}
                        type="text"
                        defaultValue={user.title}
                        onBlur={handleChange}
                        required
                    />
                </label>
            </div>
            <div>
                <input type="submit" value="Save" />
            </div> 
        </form>
    );
};

export default ProfileForm; 

我的Appframe / index.js

import './AppFrame.css';

import React from 'react';
import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom';
import loadable from '@loadable/component';

import Header from '../Header';

/* istanbul ignore next */
const Rooms = loadable(() => import('../Rooms'));

/* istanbul ignore next */
const Room = loadable(() => import('../Room'));

/* istanbul ignore next */
const RoomForm = loadable(() => import('../RoomForm'));

/* instanbul ignore next */
const Profile = loadable(() => import('../Profile'));

/* instanbul ignore next */
const ProfileForm = loadable(() => import('../ProfileForm'))

const AppFrame = () => {
    return (
        <Router>
            <Header />
            <nav className="app-navigation">
                <ol>
                    <li>
                        <NavLink to="/">Home</NavLink>
                    </li>
                    <li>
                        <NavLink to="/rooms">Room List</NavLink>
                    </li>
                    <li>
                        <NavLink to="/create-room">Create a room</NavLink>
                    </li>
                </ol>
            </nav>
            <Route path="/r/:code" exact component={Room} />
            <Route path="/rooms" component={Rooms} />
            <Route path="/create-room" exact component={RoomForm} />
            <Route path="/edit-room/:code" exact component={RoomForm} />
            <Route path="/profile" exact component={Profile} />
            <Route path="/edit-user/:nickname" exact component={ProfileForm} />
        </Router>
    );
};

export default AppFrame;

我的用户json数据

{
active: false
code: "y5bJUwc4Ho"
createdAt: "2020-05-16T18:02:16.430Z"
nickname: "Miles Davis"
online: true
updatedAt: "2020-05-16T18:02:16.430Z"
__v: 0
_id: "3839383838"
__proto__: Object
}

我得到的错误

index.js?d113:43 GET https://localhost:7000/profile/undefined 404 (Not Found)

1 个答案:

答案 0 :(得分:1)

您错过了在Appframe / index.js中向路径添加nickname参数。 更改:

<Route path="/profile/:nickname" exact component={Profile} />

收件人:

<Route path="/profile/:nickname" exact component={Profile} />

并在useEffect下的ProfileForm中更新为:

useEffect(() => {
    form.current.reset();
    const {nickname} = useParams();
    if (nickname) {
        const abortController = new AbortController();
        const getUser = async () => {
            const url = `/profile/${nickname}`;
            const res = await fetch(url, {
                method: 'GET',
                headers: { Accept: 'application/json' },
                signal: abortController.signal
            });
            if (res.ok && !abortController.signal.aborted) {
                const result = await res.json();
                setUser(result);
            }
        };

        getUser();
        return function cleanup() {
            abortController.abort();
        };
    }
}, []);