I'm new to react hooks. I'm trying to use the following component as the filter input element for one of the columns in a ReactTable component.
import React, { useState } from 'react'
import DatePicker from 'material-ui/DatePicker/DatePickerDialog'
import '../styles/style.less'
export default function DateRange({ startLabel = 'From', endLabel = 'To' } = {}) {
const [open, setOpen] = useState(false)
return (
<div className="date-range">
<input type="text" placeholder={startLabel} onClick={() => setOpen(true)} />
<input type="text" placeholder={endLabel} />
<DatePicker open={open} />
</div>
)
}
but the render fails with the following error:
Uncaught Invariant Violation: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
Related
Here I have a Loading screen as a functional react component that I try to render conditionally in the App component.
The concept of this loading screen is that I have a boolean variable that will be used to conditionally render the home page after the loading screen ends.
import React from 'react';
import { useState, useEffect } from 'react';
import { useSpring, animated } from 'react-spring';
import BarLoader from 'react-spinners/BarLoader';
import Logo from "../assets/images/logo.svg";
const LoadingScreen = () => {
const spinner = `
display: block;
margin: 0 auto;
width: 150px;
height: 2.5px;
`;
const style = useSpring({opacity: 1, from: {opacity: 0}});
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false)
}, 4000)
}, [])
const LoadingTemplate = () => {
<animated.div className="loading-screen" style={style}>
<div className="loader-wrapper">
<img className="splash-logo" src={Logo} alt="Marouane Edghoughi" />
<BarLoader color="#384BEB" css={ spinner } loading={isLoading} />
</div>
</animated.div>
}
return { LoadingTemplate, isLoading }
}
export default LoadingScreen;
When I try to call the boolean variable and the screen template in the following code:
render() {
const {LoadingTemplate, isLoading} = LoadingScreen();
return (
<Router>
{
isLoading ?
<LoadingTemplate />
:
<Container className="theme p-0" fluid={true}>
{/* something will be displayed here */}
</Container>
}
</Router>
);
}
}
I just get this error:
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
The function is working properly if I try to call it from a functional component. This is my first time trying it with a class.
Any help would be greatly appreciated ^_^
The error message is 100% correct. Hooks can be used only in Function Components, and cannot be used like this in class components. The underlying mechanics of the two types are different. Hooks are a feature of functional components and rely on those mechanics, and are therefore not compatible with class components.
You may not realize that you are using a hook, but LoadingScreen actually is one: It returns a value other than a React Element, and you are calling it as a function (i.e. const x = LoadingScreen()), rather than using it as a component (i.e. <LoadingScreen />).
That's definitely not allowed in class components. You could use a function component instead:
const Component = () => {
const {LoadingTemplate, isLoading} = LoadingScreen();
return (
<Router>
{
isLoading ?
<LoadingTemplate />
:
<Container className="theme p-0" fluid={true}>
{/* something will be displayed here */}
</Container>
}
</Router>
);
}
}
Or you can try these methods to get around this limitation. If you do decide to use a function component instead, then you should use useLoadingScreen to follow the React hook naming conventions.
I want to push some text to url route in onChange method of an input like this :
function Header(props) {
return (
<div>
<input type="radio" onChange={ (e)=> props.history.push(`/${e.target.value}`) } >
</div>
)
But it throws multiple errors and crashes :
TypeError: Cannot read property 'push' of undefined
How can use history.push properly or how can I push some text to route url manually from anywhere in react ?
Error message suggests that history prop is undefined, meaning its not passed to your component as a prop which can happen depending on the hierarchy of the components in your app.
Use one of the following options to get access to history:
Use useHistory hook
import { useHistory } from 'react-router-dom';
function Header(props) {
const routerHistory = useHistory();
return (
<div>
<input type="radio" onChange={(e)=> routerHistory.push(`/${e.target.value}`)}>
</div>
)
}
Use withRouter higher order component
import { withRouter } from 'react-router-dom';
function Header(props) {
return (
<div>
<input type="radio" onChange={(e)=> props.history.push(`/${e.target.value}`)}>
</div>
)
}
export default withRouter(Header);
For details on withRouter and useHistory, see:
React Router - useHistory Hook
React Router - withRouter
This, React Native-code, is throwing an error /when button is pressed:
import React from 'react';
import {
View,
Button
} from 'react-native';
const handleClick = (event, {title}) => {
console.log('name of button was ', title);
}
const App = () => {
return (
<View><Button title='Test' onPress={handleClick} /></View>
);
};
export default App;
While this, React-code, isn't:
import React from 'react';
import './App.css';
import { Button } from 'semantic-ui-react';
const handleClick = (event, {title}) => {
console.log('name of button was ', title);
}
function App() {
return (
<div className="App">
<Button title='Test' onClick={handleClick} >Test</Button>
</div>
);
}
export default App;
The error in the first one is: "TypeError: undefined is not an object (evaluating '_ref.title')"
Why is that, what is the difference between React and React-Native in such a situation?
And to get similar result in React Native, how should I write the same code? That is, how to get the properties of calling element?
The React Native version has been build made with react-native cli version, pure project with no add-ons.
The React version has been made with Create React App and added with Semantic Ui, but no further add-ons.
There is no way to get the props of the calling element, unless that element decides to pass them to the callback. In your case, it's a feature of semantic-ui-react's Button component - see the documentation of its onClick prop.
So you need to replace replace the code in your react-native example with something like this to explicitly pass the title:
onClick={e => handleClick(e, {title: 'Test'})}
or simplify it as onClick={e => handleClick(e, 'Test')} and remove the object unpacking in handleClick if all you need is the title.
I have two functional components in my process. First, I need the first component info to be filled and validated by Formik and Yup and then user can process the next step in the second component by click Next. For now, I can get everything validated and code can reach on handleSubmit() without any problem. But, the problem is that, I could not link to another component using <Link>. I have tried:
// Using this first one, no validation is performed and it will link to another component directly
<Link to="/Next">
<button type="submit">Next</Button>
</Link>
// I have put these inside handleSubmit() but it is undefined.
this.context.router.push('/Next');
Router.push('/Next')
this.props.history.push('/Next')
Mostly I got undefined output on console using these code. It's seems like that i could not access props from functional components like i could in the react class. Here is my first component:
import React from 'react';
import { withFormik, Field } from 'formik';
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from "react-router-dom";
const MyForm = props => { const {handleSubmit} = props;
return (
<form onSubmit={handleSubmit}>
<Field type="email" name="email" placeholder="Email" />
<button type="submit">Next</button>
// <Link to="/Next">
// <button type="submit">Next</Button>
// </Link>
</Field>
);
};
const MyEnhancedForm = withFormik({
mapPropsToValues: () => ({ email: '' }),
handleSubmit: (values, formikBag) => {
// Link to next page code
},
})(MyForm);
Yes we can't use this.props in functional components but what we can do is that write the same routing logic in parent component and pass it as a prop in the functional component.
Then we can call the same function in handleSubmit().
If you are using hooks you can follow the approach described in this blog post https://dev.to/httpjunkie/programmatically-redirect-in-react-with-react-router-and-hooks-3hej in order to programmatically redirect with react-router and hooks. A summary:
Include useState in your imports:
import React, { useState } from 'react';
Inside your functional component add:
const [toNext, setToNext] = useState(false)
Inside handleSubmit add:
setToNext(true)
Inside the <form> add:
{toNext ? <Redirect to="/Next" /> : null}
I'm kind stuck on this feature that i have do implement on my app. I need to set focus in a component on componentDidMount() or something similar.
i'm already try some suggestions like:
componentDidMount(){
this.nameDiv.focus();
}
<div ref={(div) => { this.nameDiv = div; }}>
for focus or similar for (Antdesign component) focus.
or something like that:
document.getElementById("mytext").focus();
<input type="text" id="mytext"/>
usualy i'm receiveing errors on my console: "Cannot read property 'focus' of undefined"
So the question: How can i set focus on a react / antDesign component?
Please look to following code. I'm sure this would help you.
import React from "react";
import ReactDOM from "react-dom";
class TestFocus extends React.Component {
componentDidMount = () => {
this.refs.focusedInput.focus();
};
render = () =>
<React.Fragment>
<input placeholder="I don't want focus :/" />
<br />
<input ref="focusedInput" placeholder="Please focus on me :B" />
</React.Fragment>;
}
ReactDOM.render(<TestFocus />, document.getElementById("root"));
Tested with react 16.8.6 & react-dom 16.8.6
Let me know, if this helps.