以上错误发生在<Provider>组件
The above error occurred in the <Provider> component
找不到解决此问题的方法。
浏览器错误:
未捕获错误:挂钩调用无效。 Hooks只能在内部调用
功能组件的主体。这可能发生在其中一个
原因如下:
- 您的 React 和渲染器版本可能不匹配(例如 React DOM)
- 您可能违反了 Hooks 规则
- 您可能在同一个应用程序中有多个 React 副本请参阅 https://reactjs.org/link/invalid-hook-call 以获取有关如何
调试并修复此问题。
组件出现以上错误:
Provider@http://localhost:3000/static/js/bundle.js:49534:15
考虑向树中添加错误边界以自定义错误
处理行为。访问 https://reactjs.org/link/error-boundaries
了解有关错误边界的更多信息。
INDEX.JS
import React from 'react';
import ReactDOM from 'react-dom';
import Router from './Router';
import { createStore } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import { Provider } from 'react-redux'
import rootReducer from './Redux/Reducers/index.js'
const store = createStore( rootReducer, composeWithDevTools() )
ReactDOM.render(
<Provider store={ store }>
<Router />
</Provider >,
document.getElementById( 'root' ) );
Reducers/index.js
import loginPageReducer from './LoginPage.js'
import { combineReducers } from 'redux'
const rootReducer = combineReducers( {
loginPageReducer
} )
export default rootReducer
Reducers/LoginPage.js
const INIT_STATE = {
view: 'login',
msg: '',
loader: false,
}
const loginPageReducer = ( state = INIT_STATE, action ) =>
{
switch ( action.type )
{
case "LOADER_OFF":
return state.loader = false
case "LOADER_ON":
return state.loader = true
case "MSG_SET":
return state.msg = action.msg
case "MSG_CLEAR":
return state.msg = ''
case "VIEW_CHANGE":
return state.view = action.view
default:
return state;
}
}
export default loginPageReducer
登录页面组件
import React, { useState } from 'react'
import '../Styles/loginPage.scss'
import axios from 'axios'
import { useDispatch, useSelector } from 'react-redux'
import loginPageActions from '../Redux/actions/LoginPage'
export default function LoginPage ()
{
const { msg_clear, msg_set, loader_off, loader_on, view_change } = loginPageActions
const msg = useSelector( state => state.LoginPageReducer.msg )
const view = useSelector( state => state.LoginPageReducer.view )
const loader = useSelector( state => state.LoginPageReducer.loader )
const dispatch = useDispatch()
const [inputs, setInputs] = useState( {
username: '',
password: '',
password2: '',
email: ''
} )
const handleInputs = function ( e )
{
const { name, value } = e.target
setInputs( { ...inputs, [name]: value } )
}
const handleSubmit = async ( e ) =>
{
try
{
e.preventDefault();
dispatch( msg_clear() )
dispatch( loader_on() )
if ( view === login)
{
// logowanie
const query = await axios( {
method: 'post',
url: '/api/users/login',
data: {
username: inputs.username,
password: inputs.password
}
} )
const token = query.data.token
localStorage.setItem( "token", token );
return window.location.href = "/kalkulator"
}
else
{
//rejestracja
const query = await axios( {
method: 'post',
url: '/api/users/register',
data: {
username: inputs.username,
password: inputs.password,
password2: inputs.password2,
email: inputs.email
}
} )
if ( query.status === 200 )
{
dispatch( msg_set( 'Zarejestrowano, możesz się zalogować' ) )
dispatch( view_change( true ) )
}
}
}
catch ( err )
{
if ( err ) return dispatch( msg_set( err.response.data.msg ) )
}
finally
{
dispatch( loader_off() )
}
}
/////////////
/// Renderowanie widoku
/////////////
return (
<main>
<div id="MainContainerStyle">
<span id="thatWhitePartOnBottom"></span>
<header>
<h1 id="HeaderH1" >Kalkulator mas</h1>
</header>
<button className="Buttons" onClick={ () => dispatch( view_change( !view ) ) }>
{ view ?
`Already have account? Click to log in!`
:
`Doesn't have account? Click me if you want to register new one` }
</button>
<form onSubmit={ handleSubmit } id="Form">
<input type="text"
value={ inputs.username }
placeholder={ view ? 'username' : 'Login or E-mail' }
name="username" required onChange={ handleInputs }
/>
{ view ?
<input type="email"
placeholder="email"
name="email"
value={ inputs.email }
required
onChange={ handleInputs } />
:
null
}
<input type="password"
value={ inputs.password }
placeholder="Password:"
name="password"
required
onChange={ handleInputs }
/>
{ view ?
<input type="password"
value={ inputs.password2 }
placeholder="Password again:"
name="password2"
required
onChange={ handleInputs } />
:
null
}
<input type="submit" className="Buttons" />
{ loader ? <span className="loader"></span> : null }
{ msg !== '' ? <p className="msg">{ msg }</p> : null }
</form>
</div>
</main>
)
}
路由器
import { BrowserRouter, Routes, Route } from "react-router-dom";
import './Styles/global.scss'
import LoginPage from "./Pages/LoginPage";
import Kalkulator from "./Pages/Kalkulator";
function App ()
{
return (
<>
<BrowserRouter>
<Routes>
<Route path="/" element={ <LoginPage /> } />
<Route path="/kalkulator" element={ <Kalkulator /> } />
</Routes>
</BrowserRouter>
</>
)
}
export default App;
可能是这个问题:https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react
假设 myapp 和 mylib 是兄弟文件夹,一种可能的解决方法是 运行 npm link ../myapp/node_modules/react 来自 mylib。这应该使库使用应用程序的 React 副本。
..或者可能没有安装“react-redux”,检查package.json
找不到解决此问题的方法。
浏览器错误:
未捕获错误:挂钩调用无效。 Hooks只能在内部调用 功能组件的主体。这可能发生在其中一个 原因如下:
- 您的 React 和渲染器版本可能不匹配(例如 React DOM)
- 您可能违反了 Hooks 规则
- 您可能在同一个应用程序中有多个 React 副本请参阅 https://reactjs.org/link/invalid-hook-call 以获取有关如何 调试并修复此问题。
组件出现以上错误:
Provider@http://localhost:3000/static/js/bundle.js:49534:15
考虑向树中添加错误边界以自定义错误 处理行为。访问 https://reactjs.org/link/error-boundaries 了解有关错误边界的更多信息。
INDEX.JS
import React from 'react';
import ReactDOM from 'react-dom';
import Router from './Router';
import { createStore } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import { Provider } from 'react-redux'
import rootReducer from './Redux/Reducers/index.js'
const store = createStore( rootReducer, composeWithDevTools() )
ReactDOM.render(
<Provider store={ store }>
<Router />
</Provider >,
document.getElementById( 'root' ) );
Reducers/index.js
import loginPageReducer from './LoginPage.js'
import { combineReducers } from 'redux'
const rootReducer = combineReducers( {
loginPageReducer
} )
export default rootReducer
Reducers/LoginPage.js
const INIT_STATE = {
view: 'login',
msg: '',
loader: false,
}
const loginPageReducer = ( state = INIT_STATE, action ) =>
{
switch ( action.type )
{
case "LOADER_OFF":
return state.loader = false
case "LOADER_ON":
return state.loader = true
case "MSG_SET":
return state.msg = action.msg
case "MSG_CLEAR":
return state.msg = ''
case "VIEW_CHANGE":
return state.view = action.view
default:
return state;
}
}
export default loginPageReducer
登录页面组件
import React, { useState } from 'react'
import '../Styles/loginPage.scss'
import axios from 'axios'
import { useDispatch, useSelector } from 'react-redux'
import loginPageActions from '../Redux/actions/LoginPage'
export default function LoginPage ()
{
const { msg_clear, msg_set, loader_off, loader_on, view_change } = loginPageActions
const msg = useSelector( state => state.LoginPageReducer.msg )
const view = useSelector( state => state.LoginPageReducer.view )
const loader = useSelector( state => state.LoginPageReducer.loader )
const dispatch = useDispatch()
const [inputs, setInputs] = useState( {
username: '',
password: '',
password2: '',
email: ''
} )
const handleInputs = function ( e )
{
const { name, value } = e.target
setInputs( { ...inputs, [name]: value } )
}
const handleSubmit = async ( e ) =>
{
try
{
e.preventDefault();
dispatch( msg_clear() )
dispatch( loader_on() )
if ( view === login)
{
// logowanie
const query = await axios( {
method: 'post',
url: '/api/users/login',
data: {
username: inputs.username,
password: inputs.password
}
} )
const token = query.data.token
localStorage.setItem( "token", token );
return window.location.href = "/kalkulator"
}
else
{
//rejestracja
const query = await axios( {
method: 'post',
url: '/api/users/register',
data: {
username: inputs.username,
password: inputs.password,
password2: inputs.password2,
email: inputs.email
}
} )
if ( query.status === 200 )
{
dispatch( msg_set( 'Zarejestrowano, możesz się zalogować' ) )
dispatch( view_change( true ) )
}
}
}
catch ( err )
{
if ( err ) return dispatch( msg_set( err.response.data.msg ) )
}
finally
{
dispatch( loader_off() )
}
}
/////////////
/// Renderowanie widoku
/////////////
return (
<main>
<div id="MainContainerStyle">
<span id="thatWhitePartOnBottom"></span>
<header>
<h1 id="HeaderH1" >Kalkulator mas</h1>
</header>
<button className="Buttons" onClick={ () => dispatch( view_change( !view ) ) }>
{ view ?
`Already have account? Click to log in!`
:
`Doesn't have account? Click me if you want to register new one` }
</button>
<form onSubmit={ handleSubmit } id="Form">
<input type="text"
value={ inputs.username }
placeholder={ view ? 'username' : 'Login or E-mail' }
name="username" required onChange={ handleInputs }
/>
{ view ?
<input type="email"
placeholder="email"
name="email"
value={ inputs.email }
required
onChange={ handleInputs } />
:
null
}
<input type="password"
value={ inputs.password }
placeholder="Password:"
name="password"
required
onChange={ handleInputs }
/>
{ view ?
<input type="password"
value={ inputs.password2 }
placeholder="Password again:"
name="password2"
required
onChange={ handleInputs } />
:
null
}
<input type="submit" className="Buttons" />
{ loader ? <span className="loader"></span> : null }
{ msg !== '' ? <p className="msg">{ msg }</p> : null }
</form>
</div>
</main>
)
}
路由器
import { BrowserRouter, Routes, Route } from "react-router-dom";
import './Styles/global.scss'
import LoginPage from "./Pages/LoginPage";
import Kalkulator from "./Pages/Kalkulator";
function App ()
{
return (
<>
<BrowserRouter>
<Routes>
<Route path="/" element={ <LoginPage /> } />
<Route path="/kalkulator" element={ <Kalkulator /> } />
</Routes>
</BrowserRouter>
</>
)
}
export default App;
可能是这个问题:https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react
假设 myapp 和 mylib 是兄弟文件夹,一种可能的解决方法是 运行 npm link ../myapp/node_modules/react 来自 mylib。这应该使库使用应用程序的 React 副本。
..或者可能没有安装“react-redux”,检查package.json