出现错误:渲染的钩子比预期少

问题描述 投票:0回答:1

我收到此错误:

Uncaught runtime errors:

ERROR
Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
    at renderWithHooks (http://localhost:3000/static/js/bundle.js:28072:15)
    at updateFunctionComponent (http://localhost:3000/static/js/bundle.js:31574:24)
    at beginWork (http://localhost:3000/static/js/bundle.js:33293:20)
    at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:18263:18)
    at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:18307:20)
    at invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:18364:35)
    at beginWork$1 (http://localhost:3000/static/js/bundle.js:38262:11)
    at performUnitOfWork (http://localhost:3000/static/js/bundle.js:37510:16)
    at workLoopSync (http://localhost:3000/static/js/bundle.js:37433:9)
    at renderRootSync (http://localhost:3000/static/js/bundle.js:37406:11

根据我所读到的内容,如果在条件语句中调用钩子,或者如果我将 return 语句放在钩子调用之上,等等,就会发生这种情况。

当我单击此按钮时会引发错误(这应该将我导航到另一个页面):

<Col xs={1} className="myCol"><Button variant="info" value={v.id} onClick={(e) => requestMemberEdit(e.target.value, 'edit')}>Edit</Button></Col>

点击按钮时调用的函数是这样的:

const requestMemberEdit = (id, type) => {
    navigate("/newmember", { state:{type:type, id: id }} );       
}

在另一个文件中,我尝试使用

location
来获取单击按钮时发送的状态属性。

这是第一个文件的完整代码,其中包含我上面刚刚显示的代码(这是引发错误的代码)

import { useState, useEffect } from "react";
import { Container, Row, Col, Button } from 'react-bootstrap';
import { useNavigate } from "react-router-dom";

const ShowMembers = () => {    
    const [allMembers, setAllMembers] = useState({});    
    const [arg, setArg] = useState('');         
    const navigate = useNavigate();
    
    useEffect(() => {
        const getAllMembers = () => {            
            fetch('/getAllMembers')
            .then(data => data.json())
            .then(res => {            
                setAllMembers(res)
                //console.log(allMembers)
            })
            .catch(err => {
                console.log(err)
            })
        };
        getAllMembers();
    }, []);                            
    
    const requestMemberEdit = (id, type) => {
        //console.log('xxxxxx ' + id)
        navigate("/newmember", { state:{type:type, id: id }} );       
    }

    const requestMemberDelete = (id) => {
        if(window.confirm("Delete this member?")) {
            fetch("/api/deleteMember", {
                method: 'post',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({id: parseInt(id)})
            })
            .then(res => res.json())
            .then(res => {
                res === true ? alert("User deleted")
                    : alert("Something went wrong, pls try again");
            })            
        }
    }        
        
    return (
        <>       
        <div className="memberDiv">
            <Container className="members">                        
            {
                allMembers.length ?                     
                    allMembers.map(v => <Row key={v.id}>                                            
                                            <Col className="myCol">{v.firstname}</Col>
                                            <Col className="myCol">{v.lastname}</Col>
                                            <Col className="myCol">{v.email}</Col>
                                            <Col className="myCol">{v.birthdate}</Col>
                                            <Col xs={1} className="myCol"><Button variant="danger" value={v.id} onClick={(e) => requestMemberDelete(e.target.value)}>Delete</Button></Col>
                                            <Col xs={1} className="myCol"><Button variant="info" value={v.id} onClick={(e) => requestMemberEdit(e.target.value, 'edit')}>Edit</Button></Col>
                                            
                                        </Row>)
                : <h2>No data</h2>
            }
            </Container>
        </div>

        </>
    )
}

export default ShowMembers;

如果您注意到此代码:

const [arg, setArg] = useState('');
。我不在任何地方使用它。我想删除它,并注意到删除后,它会给出另一条错误消息。此错误消息是:

Should have a queue. This is likely a bug in React. Please file an issue.
at updateReducer (http://localhost:3000/static/js/bundle.js:28232:15)
at updateState (http://localhost:3000/static/js/bundle.js:28600:14)
at Object.useState (http://localhost:3000/static/js/bundle.js:29397:20)
at useState (http://localhost:3000/static/js/bundle.js:47840:25)
at AddMember (http://localhost:3000/static/js/bundle.js:1161:84)
at renderPage (http://localhost:3000/static/js/bundle.js:289:70)
at Content (http://localhost:3000/static/js/bundle.js:302:10)
at renderWithHooks (http://localhost:3000/static/js/bundle.js:28005:22)
at updateFunctionComponent (http://localhost:3000/static/js/bundle.js:31572:24)
at beginWork (http://localhost:3000/static/js/bundle.js:33291:20)

尽管它说这可能是 React 中的一个错误,但我不认为它是。

这是另一个文件中的代码,我想在其中使用

location

import { useState } from "react";
import { Row, Col, Form, Button } from "react-bootstrap";
import { useLocation } from 'react-router-dom';

const AddMember = () => {
    const [data, setData] = useState('');
    const [oldMember, setOldMember] = useState('')
    const location = useLocation();

    console.log(location)

    if(location.type === 'edit') {
        fetch('/api/getMemberByID', {
            method: 'post',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({id: location.id})
        })
        .then(data => data.json())
        .then(res => {
            setOldMember(res)
        })
        .catch(err => {
            console.log('Could not set old member')
        })
    }

    const handleChange = (e) => {
        const { name, value } = e.target;
        setData((prevData) => ({
            ...prevData,
            [name]: value,
        }));
    };

    const submitFormData = async (e) => {
        e.preventDefault();

        await fetch('/newmember', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(data)
        })
            .then(res => res.json())
            .then(data => {
                console.log("ffff:"+data);
            })
            .catch(err => {
                console.log(err)
            })
    };

    return (
        <div className="contentDiv">
            <Form onSubmit={submitFormData} name="formdata" id="formdata">
                <Form.Group className="mb-3" controlId="formBasicEmail">
                    <Row>
                        <Col>
                            <Form.Label>First name</Form.Label>
                            <Form.Control type="text" placeholder="Fornavn" value={oldMember ? oldMember.firstname : ''} name="firstname" required onChange={handleChange} />
                        </Col>
                        <Col>
                            <Form.Label>Last name</Form.Label>
                            <Form.Control type="text" placeholder="Efternavn" value={oldMember ? oldMember.lastname : ''} name="lastname" required onChange={handleChange} />
                        </Col>
                        <Col>
                            <Form.Label>Email</Form.Label>
                            <Form.Control type="text" placeholder="Email" value={oldMember ? oldMember.email : ''} name="email" required onChange={handleChange} />
                        </Col>
                    </Row>

                    <Row>
                        <Col>
                            <Form.Label>Birthday</Form.Label>
                            <Form.Control type="date" placeholder="Fødselsdag" name="bday" required onChange={handleChange} />
                        </Col>
                        <Col>
                            <Form.Label>Sport</Form.Label>
                            <Form.Select aria-label="Default select example" name="sport" type="number" onChange={handleChange} >
                                <option>Vælg aktivitet</option>
                                <option value="1">Hobby 1</option>
                                <option value="2">Hobby 2</option>
                                <option value="3">Hobby 3</option>
                            </Form.Select>
                        </Col>
                        <Col>                            
                            <Form.Check type="checkbox" name="active" label="Active" onChange={handleChange} />
                        </Col>
                    </Row>

                    <Row>
                        <Col>
                            <Form.Label>Chip</Form.Label>
                            <Form.Control type="text" name="chip" placeholder="Add chip" onChange={handleChange}/>
                        </Col>
                    </Row>
                </Form.Group>

                <Button type="submit"> Submit</Button>
            </Form>
        </div>
    )
}

export default AddMember;

如果它很重要,我正在使用

BrowserRouter

 function App() {  
  return (
    <>
      <Buttons />
      <BrowserRouter>
        <Routes>
          <Route path='/' element={<Content />}></Route>
          <Route path='/newmember' element={<Content />}></Route>         
          <Route path='/ShowMembers' element={<Content />}></Route>
          <Route path='/ShowAdmins' element={<Content />}></Route>
          <Route path='/NewAdmin' element={<Content />}></Route>
          <Route path='*' element={<PageNotFound />}></Route>
        </Routes>
      </BrowserRouter>
    </>
  );
}

export default App;
reactjs react-hooks
1个回答
0
投票
上面的

<Content />

 函数中引用的我的 
App()
 组件看起来像这样:

const Content = () => { const URL = window.location.pathname.split('/')[1]; const renderPage = (url) => { switch (url) { case 'newmember': return AddMember() case 'NewAdmin': return AddAdmin() case 'showMemberByMail': return ShowMembers() case 'ShowMembers': return ShowMembers() case 'ShowAdmins': return ShowAdmins() default: return PageNotFound() } } return ( renderPage(URL) ) }
作为 React 新手,我并没有考虑在组件上使用 JSX 语法,所以相反,我最终像常规函数一样调用它们,这导致了奇怪的行为,尤其是上面描述的问题,这就是这篇文章的原因。 

所以我解决这个问题的方法是使用 JSX 语法渲染组件。这是现在的样子,解决了我的头痛/问题

const Content = () => { const URL = window.location.pathname.split('/')[1]; const renderPage = (url) => { switch (url) { case 'newmember': return <AddMember /> case 'NewAdmin': return <AddAdmin /> case 'showMemberByMail': return <ShowMembers /> case 'ShowMembers': return <ShowMembers /> case 'ShowAdmins': return <ShowAdmins /> default: return <PageNotFound /> } } return ( renderPage(URL) ) }
如果我将此文件与上面的其他文件一起发布,人们可能会发现我的问题,但我不知道这个文件/代码会是问题

© www.soinside.com 2019 - 2024. All rights reserved.