【问题标题】:I want to navigate to a page/component where I passed the data from another component using both React hooks and useHistory, but I get undefined我想导航到一个页面/组件,在该页面/组件中我使用 React 钩子和 useHistory 从另一个组件传递了数据,但我得到了未定义
【发布时间】:2021-10-21 10:35:00
【问题描述】:

到目前为止,我是新来的反应 3 周。 登录到我的虚拟应用程序后,我从数据库(useEffect)中获取用户作为按钮。我想单击特定用户并在下一页访问他/她的数据。因此,我使用 context API 和 useHistory 分别将所选用户的数据(状态)发送到组件,并使用 usehistory 导航到该组件。但是,当路由到该组件时,我会收到未定义的数据,因为我可以访问该组件。

    import React, { useState, useEffect } from 'react';
    import { useHistory } from 'react-router-dom';
    import axios from 'axios';
    import { useToken } from '../auth/useToken';
    import { useUser } from '../auth/useUser';
    import { ClassDetails } from './ClassPages/ClassDetails';

    export const classSelectedContext = React.createContext();
    
    export const ClassSelection = () => {
    
        const user = useUser();
        const [token, setToken] = useToken();
        const [classesList, setClassesList] = useState([]);
        const [selectedClass, setSelectedClass] = useState('');
        const [className, setClassName] = useState('');
        const [startDate, setStartDate] = useState('');
        const [endDate, setEndDate] = useState('');
    
        const history = useHistory();
        
        const authStr = 'Bearer '.concat(token); 
    
        useEffect( () =>{
            axios.get('http://localhost:8081/user/instructor-classes',  {
                headers: {
                    'Authorization': authStr
                }
            })
            .then (res => {
                setClassesList(res.data);
            })
            .catch(
                err =>{
                    console.log(err);
                    history.push("/")
                }
            );
        
        },[selectedClass]);
        
        const AddNewClassClicked = () => {
            axios.post('http://localhost:8081/user/class', {
                className: className,
                startDate: startDate,
                endDate: endDate,
            }, {
                headers : {
                    'Authorization': authStr,
                    'Content-Type': 'application/json',
                }
            } )
            .then(
                //window.location.reload()
            )
            .catch(err => {
                console.log(err)
            });
       }
    
            const onSelectedClassClicked = () =>{
                  {history.push('class-detail')} 
            }
    
    
        return (
            <div className="content-container">
                <div className="content-container">
    
                    <h1>Your current classes</h1>
                        {classesList.map(item => (
                        <button 
                            value={item.classIdentifier}
                            onClick={(e) => {
                                setSelectedClass(e.target.value)
                                onSelectedClassClicked()
                            }}>
                            {item.className}
                        </button>
                        
                        )) } 
                    <classSelectedContext.Provider value={selectedClass} >
                        <ClassDetails />
                    </classSelectedContext.Provider>
                    
                </div>
    
                <div className="content-container">
                    <h1>Add a new Class</h1>
                    <input
                        value={className}
                        onChange={e => setClassName(e.target.value)}
                        placeholder="Class Name" />
                    <input
                        value={startDate}
                        onChange={e => setStartDate(e.target.value)}
                        placeholder="Start Date of the Class" /> 
                    <input
                        value={endDate}
                        onChange={e => setEndDate(e.target.value)}
                        placeholder="End Date of the Class" />               
                    
                    <button
                        disabled={
                            !className || !startDate ||
                            !endDate 
                        }
                    onClick={AddNewClassClicked}>add new Class</button>
                </div>
            </div>
        )
    
    }

所以,在单击按钮后,我使用历史记录来访问 ClassDetails(类详细信息),在那里我可以通过 useEffect 钩子获取传递给该组件的数据。

    import React from 'react';
    import { useState, useEffect, useContext } from 'react';
    import { classSelectedContext } from '../ClassSelection';
    import axios from 'axios';
    import { useHistory } from 'react-router-dom';
    import { useToken } from '../../auth/useToken';

    export const ClassDetails = () => {
        
        const [token, setToken] = useToken();
    
        const history = useHistory();
        const authStr = 'Bearer '.concat(token); 
        let context = useContext(classSelectedContext);
    
    
        useEffect( () =>{
            console.log(context)
        
            axios.get(`http://localhost:8081/user/class/${context}`,  {
                headers: {
                    'Authorization': authStr
                }
            })
            .then (res => {  
                console.log(res.data);
            })
            .catch(
                err =>{
                    console.log(err);
                    console.log("An error happenned")
                }
            );
         }, []);
       
        return (
            <div>
                welcome {context}
                <div>
                    { GetClassDetail(context) }
                </div>
                {/* <classSelectedContext.Consumer>
                    {
                        
                        variable => { GetClassDetail(variable)}
                    }
                </classSelectedContext.Consumer> */}
           </div>
        )
    }

最后,这些是我的路线

    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    import { LogInPage } from './pages/LogInPage';
    import { SignUpPage } from './pages/SignUpPage';
    import { UserInfoPage } from './pages/UserInfoPage';
    import { PrivateRoute } from './auth/PrivateRoute';
    import { ClassSelection } from './pages/ClassSelection';
    import { WelcomePage } from './pages/WelcomePage';
    import { UserLogIn } from './pages/UserLogIn';
    import { ClassDetails } from './pages/ClassPages/ClassDetails';

    export const Routes = () => {
        return (
            <Router>
                <Switch>
                    <PrivateRoute path="/class-detail" exact>
                        <ClassDetails />
                    </PrivateRoute> 
                    <PrivateRoute path="/instructor-classes" exact>
                        <ClassSelection />
                    </PrivateRoute>
                    <PrivateRoute path="/select-school" exact>
                        <UserInfoPage />
                    </PrivateRoute>
                    <Route path="/user-login">
                        <UserLogIn />
                    </Route>
                    <Route path="/teacher-login">
                        <LogInPage />
                    </Route>
                    <Route path="/">
                        <WelcomePage />
                    </Route>                
                    <Route path="/signup">
                        <SignUpPage />
                    </Route>
                </Switch>
            </Router>
        );
    }

【问题讨论】:

    标签: reactjs react-hooks use-effect


    【解决方案1】:

    请查看代码in this codesandbox link。我试图创建一个您正在尝试制作的小型应用程序。我已经为路由器添加了一个上下文包装器,以便它可以在路由更改时使用。您也可以使用 render prop 并添加带有单个组件的提供程序,如下面的代码。

    &lt;Route path="/" render={(props) =&gt; (&lt;ContextB&gt;&lt;Component2 {...props}/&gt;&lt;/ContextB&gt;)}/&gt;

    只有当组件被包裹在里面时,历史才会起作用 你的代码中的“react router dom”可能是你正在处理的。

    【讨论】:

      【解决方案2】:

      太棒了。我需要将超过 1 个参数传递给 useHistory 钩子并使用 uselocation 来获取参数:

        history.push({
                  pathname: "/class-detail",
                  search: "?id=someId",
                  hash: "#someHash",
                  state: { someState}
                })
      

      那么我可以在你希望使用状态的组件中通过以下方式使用 useLocation 钩子:

      let context = useLocation(history.state);
      console.log(context) //this will give you a Json of the history you pushed.
      

      【讨论】:

        【解决方案3】:

        一个想法——你没有在你的 async/await 按钮点击 axios 调用。 onSelectedClassClicked 是否会运行,在 axios 调用返回任何数据之前将您推送到类详细信息组件,因此您的 classDetails 将保持未定义?

        此外,您似乎在 AddNewClassClicked 块周围缺少一组大括号,看起来 onSelectedClassClicked 在该函数中。

        【讨论】:

        • 我修复了括号问题,但是 await/async 是 Promise/then/catch 的同义词。不是吗?
        • 这是推动我知识的前沿,但如果我不得不猜测 - 是的,它是同义词,但在你的按钮 onClick 函数中,你需要表明你正在等待 useeffect 函数的承诺正在返回。 then/catch 用于等待 axios 函数返回。可能类似于:``` ```
        • 我认为归结为以下问题:使用useHistory钩子更改组件时上下文API是否有效?
        • 看起来可以尝试使用 useLocation 而不是 useHistory 来触发重新渲染? stackoverflow.com/questions/66875410/…
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-07
        • 1970-01-01
        • 1970-01-01
        • 2016-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多