const [bgColor, setBgColor] = useState('black');
class Accelerons extends Component {
constructor(props) {
super(props);
}
componentDidMount = () => {
$(window).on('scroll touchmove', function () {
if ($(document).scrollTop() >= $('.about-us').position().top) {
setBgColor('red');
}
});
};
render() {
return (
<article
style={{
backgroundColor: bgColor,
}}
>
<Overlay />
<Landing landing={DataAccelerons.landing} />
<AboutUs itemColor={itemColor} accelerons={DataAccelerons} />
<Participation itemColor={itemColor} accelerons={DataAccelerons} />
<TeamMembers itemColor={itemColor} accelerons={DataAccelerons} />
<Results itemColor={itemColor} accelerons={DataAccelerons} />
<Footer
accentColor={DataAccelerons.accentColor}
footerColors={DataAccelerons.footerColors}
/>
</article>
);
}
}
export default Accelerons;
This gives me an error that we can't use react hooks at the starting ,but if I declare them in render it won't be recognized by ComponentDidMount function ReactJS
You can use hooks such as useState only inside functional component whereas setState in the lifecycles in Class components. You don't wanna mix two. A typical usage would go something like this:
import React, { useState } from 'react';
function Example() {
const [myVal, setMyVal] = useState('Hello World');
return (
<div>
<p>{myVal}</p>
</div>
);
}
Read More
If you want to go with lifecycle methods (such as componentDidMount), you may consider using seState. Also, you can't use setState inside render method as it would trigger an infinite call.
React hook can be used only functional component whereas componentDidMount is the life cycle method for class based component.
Related
Goal
I am aiming to get the transcript value, from the function Dictaphone and pass it into to the SearchBar class, and finally set the state term to transcript.
Current code
import React from 'react';
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';
const Dictaphone = () => {
const { transcript } = useSpeechRecognition()
if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
return null
}
return (
<div>
<button onClick={SpeechRecognition.startListening}>Start</button>
<p>{transcript}</p>
</div>
)
}
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
term: ''
}
this.handleTermChange = this.handleTermChange.bind(this);
}
handleTermChange(event) {
this.setState({ term: event.target.value });
}
render() {
return (
<div className="SearchBar">
<input onChange={this.handleTermChange} placeholder="Enter some text..." />
<Dictaphone />
</div>
)
}
}
export { SearchBar };
Problem
I can render the component <Dictaphone /> within my SearchBar. The only use of that is it renders a button and the transcript. But that's not use for me.
What I need to do is, get the Transcript value and set it to this.state.term so my input field within my SearchBar changes.
What I have tried
I tried creating an object within my SearchBar component and called it handleSpeech..
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
term: ''
}
this.handleTermChange = this.handleTermChange.bind(this);
}
handleTermChange(event) {
this.setState({ term: event.target.value });
}
handleSpeech() {
const { transcript } = useSpeechRecognition()
if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
return null
}
SpeechRecognition.startListening();
this.setState({ term: transcript});
}
render() {
return (
<div className="SearchBar">
<input onChange={this.handleTermChange} placeholder="Enter some text..." />
<button onClick={this.handleSpeech}>Start</button>
</div>
)
}
}
Error
But I get this error:
React Hook "useSpeechRecognition" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks
React Hooks must be called in a React function component or a custom React Hook function
Well, the error is pretty clear. You're trying to use a hook in a class component, and you can't do that.
Option 1 - Change SearchBar to a Function Component
If this is feasible, it would be my suggested solution as the library you're using appears to be built with that in mind.
Option 2
Communicate between Class Component <=> Function Component.
I'm basing this off your "current code".
import React, { useEffect } from 'react';
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';
const Dictaphone = ({ onTranscriptChange }) => {
const { transcript } = useSpeechRecognition();
// When `transcript` changes, invoke a function that will act as a callback to the parent (SearchBar)
// Note of caution: this code may not work perfectly as-is. Invoking `onTranscriptChange` would cause the parent's state to change and therefore Dictaphone would re-render, potentially causing infinite re-renders. You'll need to understand the hook's behavior to mitigate appropriately.
useEffect(() => {
onTranscriptChange(transcript);
}, [transcript]);
if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
return null
}
return (
<div>
<button onClick={SpeechRecognition.startListening}>Start</button>
<p>{transcript}</p>
</div>
)
}
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
transcript: ''
}
this.onTranscriptChange = this.onTranscriptChange.bind(this);
}
onTranscriptChange(transcript){
this.setState({ transcript });
}
render() {
return (
<div className="SearchBar">
<input onChange={this.handleTermChange} placeholder="Enter some text..." />
<Dictaphone onTranscriptChange={onTranscriptChange} />
</div>
)
}
}
useSpeechRecognition is a React hook, which is a special type of function that only works in specific situations. You can't use hooks inside a class-based component; they only work in function-based components, or in custom hooks. See the rules of hooks for all the limitations.
Since this hook is provided by a 3rd party library, you have a couple of options. One is to rewrite your search bar component to be a function. This may take some time if you're unfamiliar with hooks.
You can also see if the react-speech-recognition library provides any utilities that are intended to work with class-based components.
I have 2 functional components and, let say Parent and Child. Then I have a method doThis() inside Child component to invoke some functionality such as state update in the child. Child component is inside the parent and I need to use that as a reference using useRef() hook and call the doThis() function.
The implementation goes like this.
//Component Parent
function Parent(){
const child= useRef()
if(child.current){
child.current.doThis()
}
return( <Child ref={child}/>)
}
function Child({ref}){
// Don't know how to define
function doThis(){
//Do some task
}
return( <View/>)
}
I have seen a section called Methods in react-native documentation. Ex: scrollToIndex() in FlatList
So how to define such methods using functional components?
Forwarding refs to DOM components
Example of such component:
import { TextInput as TextInputNative } from "react-native";
import React from "react";
const TextInput = React.forwardRef(
({ ...props }, ref) => (
<TextInputNative
ref={ref}
{...props}
/>
)
);
export default TextInput;
Here how I use my component later in code:
<TextInput
ref={inputRef}
/>
To create a ref, I use useRef(null);
I am trying to toggle visiblity of a div in a stateless component like this:
const playerInfo = (props) => {
let isPanelOpen = false;
return (
<div onClick={() => isPanelOpen = !isPanelOpen }>Toggle</div>
{isPanelOpen && <div className="info-panel">
{props.children}
</div>}
);
};
I see that the value of isPanelOpen changes to true, but the panel is not being shown. I assume that is because this is the stateless function that doesn't get called again, so once we return the jsx it will have the value of false, and won't update it later.
Is there a way of fixing this, and avoiding of pasing this single variable as props through 4 more parent stateless components?
You can't tell React to re-render the UI by assigning new value directly to the variable (in your case you did isPanelOpen = !isPanelOpen).
The correct method is to use setState.
But you cannot do it in a stateless component, you must do it in a stateful component, so your code should looks like this
import React, {Component} from 'react';
class playerInfo extends Component {
constructor(props){
super(props);
this.state = {
isPanelOpen: false
}
}
render() {
return (
<div onClick={() => this.setState({isPanelOpen: !this.state.isPanelOpen})}>Toggle</div>
{this.state.isPanelOpen && <div className="info-panel">
{this.props.children}
</div>}
);
}
}
Explanation
Remember two things:
1) Your UI should only bind to this.state.XXXX (for stateful component) or props.XXX (for stateless component).
2) The only way to update UI is by calling setState() method, no other way will trigger React to re-render the UI.
But... how do I update stateless component since it doesn't have the setState method?
ONE ANSWER:The stateless component should be contained in another stateful component.
Example
Let's say your stateless component is called Kid, and you have another stateful component called Mum.
import React, {Component} from 'react';
class Mum extends Component {
constructor(props){
super(props);
this.state = {
isHappy: false
}
}
render() {
return (
<div>
<button onClick={() => this.setState({isHappy: true})}>Eat</button>
<Kid isHappy={this.state.isHappy}/>
</div>
);
}
}
const Kid = (props) => (props.isHappy ? <span>I'm happy</span> : <span>I'm sad</span>);
You can do this by using useState hooks like this:
import { useState } from "react";
function playerInfo () {
const [panel, setPanel] = useState(false);
function toggleButton () {
if(!panel) setPanel(true);
else setPanel(false);
}
return (
<div>
<button onClick={toggleButton}>Toggle</div>
panel ? {this.props.children} : null;
</div>}
);
};
export default playerInfo;
I assume that is because this is the stateless function that doesn't get called again
Basically, the only way to re-render component is to change state or props. :)
So when you change a local variable, React doesn't get notified about it and doesn't start reconcilation.
You can do this with native Javascipt otherwise in React you can not do this with stateless Component :)
const playerInfo = (props) => {
let isPanelOpen = false;
return ( <
div onClick = {
() => {
if (document.getElementsByClassName("info-panel")[0].style.display == 'none') {
isPanelOpen = true;
document.getElementsByClassName("info-panel")[0].style.display = '';
} else {
isPanelOpen = false;
document.getElementsByClassName("info-panel")[0].style.display = 'none';
}
}
} > Toggle < /div> <
div className = "info-panel" > {
this.props.children
} <
/div>
);
};
As of version 16.8 of React you can handle this for stateless components using a hook - in this case useState. In it's simplest form it can be implemented like this:
import React, { useState } from 'react';
const PlayerInfo = (props) => {
const [showPanel, togglePanel] = useState(false);
return (
<div onClick={() => togglePanel(!showPanel) }>Toggle</div>
{showPanel && (
<div className="info-panel">
{props.children}
</div>
)}
</div>
);
};
export default PlayerInfo;
A functional component will not re-render unless a previous parent's state changes and passes down updated properties that propagate down to your functional component. You can pass an onClick handler in from a stateful parent and call this from your stateless component when its onClick is triggered. The parent will control the toggling of the display and pass it in as a prop to the child (see snippet below).
To architect this, you should determine if your HOC (higher order component) should be in charge of UI state. If so, then it can make the determination if its child component should be in an open state or not and then pass that as a property to the child state. If this is a component that should open and close independent of the world around it, then it should probably have its own state. For example, if you are making a tabbed widget, it should probably be controlling its own open and closed states.
class App extends React.Component {
state= {
isOpen: false
}
handleClick = () => {
this.setState({
isOpen: !this.state.isOpen
})
}
render() {
return (
<div>
<YourComponent isOpen={this.state.isOpen} handleClick={this.handleClick} />
</div>
)
}
}
const YourComponent = ({isOpen, handleClick} = props) => {
const onClick = () => {
if (handleClick) {
handleClick();
}
}
return (
<div onClick={onClick}>
{isOpen ?
<h2>it is open</h2>
:
<h2>it is closed</h2>
}
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
If your major concern is about passing properties/methods down to too many components, you could create a pure component which will give you access to state but not all the overhead of a React Component subclass. You could also look into using a state management tool like Redux.
I have written a Higher Order Component:
import React from 'react';
const NewHOC = (PassedComponent) => {
return class extends React.Component {
render(){
return (
<div>
<PassedComponent {...this.props}/>
</div>
)
}
}
}
export default NewHOC;
I am using the above in my App.js:
import React from 'react';
import Movie from './movie/Movie';
import MyHOC from './hoc/MyHOC';
import NewHOC from './hoc/NewHOC';
export default class App extends React.Component {
render() {
return (
<div>
Hello From React!!
<NewHOC>
<Movie name="Blade Runner"></Movie>
</NewHOC>
</div>
);
}
}
But, the warning I am getting is:
Warning: Functions are not valid as a React child. This may happen if
you return a Component instead of <Component /> from render. Or maybe
you meant to call this function rather than return it.
in NewHOC (created by App)
in div (created by App)
in App
The Movie.js file is:
import React from "react";
export default class Movie extends React.Component{
render() {
return <div>
Hello from Movie {this.props.name}
{this.props.children}</div>
}
}
What am I doing wrong?
I did encounter this error too because I didn't use the correct snytax at routing. This was in my App.js under the <Routes> section:
False:
<Route path="/movies/list" exact element={ MoviesList } />
Correct:
<Route path="/movies/list" exact element={ <MoviesList/> } />
So now the MoviesList is recognized as a component.
You are using it as a regular component, but it's actually a function that returns a component.
Try doing something like this:
const NewComponent = NewHOC(Movie)
And you will use it like this:
<NewComponent someProp="someValue" />
Here is a running example:
const NewHOC = (PassedComponent) => {
return class extends React.Component {
render() {
return (
<div>
<PassedComponent {...this.props} />
</div>
)
}
}
}
const Movie = ({name}) => <div>{name}</div>
const NewComponent = NewHOC(Movie);
function App() {
return (
<div>
<NewComponent name="Kill Bill" />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"/>
So basically NewHOC is just a function that accepts a component and returns a new component that renders the component passed in. We usually use this pattern to enhance components and share logic or data.
You can read about HOCS in the docs and I also recommend reading about the difference between react elements and components
I wrote an article about the different ways and patterns of sharing logic in react.
In my case i forgot to add the () after the function name inside the render function of a react component
public render() {
let ctrl = (
<>
<div className="aaa">
{this.renderView}
</div>
</>
);
return ctrl;
};
private renderView() : JSX.Element {
// some html
};
Changing the render method, as it states in the error message to
<div className="aaa">
{this.renderView()}
</div>
fixed the problem
I encountered this error while following the instructions here: https://reactjs.org/docs/add-react-to-a-website.html
Here is what I had:
ReactDOM.render(Header, headerContainer);
It should be:
ReactDOM.render(React.createElement(Header), headerContainer);
I had this error too. The problem was how to call the function.
Wrong Code:
const Component = () => {
const id = ({match}) => <h2>Test1: {match.params.id}</h2>
return <h1>{id}</h1>;
};
Whereas id is a function, So:
Correct code:
return <h1>{id()}</h1>;
Adding to sagiv's answer, we should create the parent component in such a way that it can consist all children components rather than returning the child components in the way you were trying to return.
Try to intentiate the parent component and pass the props inside it so that all children can use it like below
const NewComponent = NewHOC(Movie);
Here NewHOC is the parent component and all its child are going to use movie as props.
But any way, you guyd6 have solved a problem for new react developers as this might be a problem that can come too and here is where they can find the solution for that.
I was able to resolve this by using my calling my high order component before exporting the class component. My problem was specifically using react-i18next and its withTranslation method, but here was the solution:
export default withTranslation()(Header);
And then I was able to call the class Component as originally I had hoped:
<Header someProp={someValue} />
it also happens when you call a function from jsx directly rather than in an event. like
it will show the error if you write like
<h1>{this.myFunc}<h2>
it will go if you write:
<h1 onClick={this.myFunc}>Hit Me</h1>
I was getting this from webpack lazy loading like this
import Loader from 'some-loader-component';
const WishlistPageComponent = loadable(() => import(/* webpackChunkName: 'WishlistPage' */'../components/WishlistView/WishlistPage'), {
fallback: Loader, // warning
});
render() {
return <WishlistPageComponent />;
}
// changed to this then it's suddenly fine
const WishlistPageComponent = loadable(() => import(/* webpackChunkName: 'WishlistPage' */'../components/WishlistView/WishlistPage'), {
fallback: '', // all good
});
In my case, I was transport class component from parent and use it inside as a prop var, using typescript and Formik, and run well like this:
Parent 1
import Parent2 from './../components/Parent2/parent2'
import Parent3 from './../components/Parent3/parent3'
export default class Parent1 extends React.Component {
render(){
<React.Fragment>
<Parent2 componentToFormik={Parent3} />
</React.Fragment>
}
}
Parent 2
export default class Parent2 extends React.Component{
render(){
const { componentToFormik } = this.props
return(
<Formik
render={(formikProps) => {
return(
<React.fragment>
{(new componentToFormik(formikProps)).render()}
</React.fragment>
)
}}
/>
)
}
}
What would be wrong with doing;
<div className="" key={index}>
{i.title}
</div>
[/*Use IIFE */]
{(function () {
if (child.children && child.children.length !== 0) {
let menu = createMenu(child.children);
console.log("nested menu", menu);
return menu;
}
})()}
In my case I forgot to remove this part '() =>'. Stupid ctrl+c+v mistake.
const Account = () => ({ name }) => {
So it should be like this:
const Account = ({ name }) => {
In my case
<Link key={uuid()} to="#" className="tag">
{post.department_name.toString}
</Link>
changed with
<Link key={uuid()} to="#" className="tag">
{post.department_name.toString()}
</Link>
You should use
const FunctionName = function (){
return (
`<div>
hello world
<div/>
`
)
};
if you use Es6 shorthand function it will give error use regular old javascript function.
Is there a way to pass one component into another react component? I want to create a model react component and pass in another react component in order to transclude that content.
Edit: Here is a reactJS codepen illustrating what I'm trying to do. http://codepen.io/aallbrig/pen/bEhjo
HTML
<div id="my-component">
<p>Hi!</p>
</div>
ReactJS
/**#jsx React.DOM*/
var BasicTransclusion = React.createClass({
render: function() {
// Below 'Added title' should be the child content of <p>Hi!</p>
return (
<div>
<p> Added title </p>
{this.props.children}
</div>
)
}
});
React.renderComponent(BasicTransclusion(), document.getElementById('my-component'));
You can use this.props.children to render whatever children the component contains:
const Wrap = ({ children }) => <div>{children}</div>
export default () => <Wrap><h1>Hello word</h1></Wrap>
Note I provided a more in-depth answer here
Runtime wrapper:
It's the most idiomatic way.
const Wrapper = ({children}) => (
<div>
<div>header</div>
<div>{children}</div>
<div>footer</div>
</div>
);
const App = () => <div>Hello</div>;
const WrappedApp = () => (
<Wrapper>
<App/>
</Wrapper>
);
Note that children is a "special prop" in React, and the example above is syntactic sugar and is (almost) equivalent to <Wrapper children={<App/>}/>
Initialization wrapper / HOC
You can use an Higher Order Component (HOC). They have been added to the official doc recently.
// Signature may look fancy but it's just
// a function that takes a component and returns a new component
const wrapHOC = (WrappedComponent) => (props) => (
<div>
<div>header</div>
<div><WrappedComponent {...props}/></div>
<div>footer</div>
</div>
)
const App = () => <div>Hello</div>;
const WrappedApp = wrapHOC(App);
This can lead to (little) better performances because the wrapper component can short-circuit the rendering one step ahead with shouldComponentUpdate, while in the case of a runtime wrapper, the children prop is likely to always be a different ReactElement and cause re-renders even if your components extend PureComponent.
Notice that connect of Redux used to be a runtime wrapper but was changed to an HOC because it permits to avoid useless re-renders if you use the pure option (which is true by default)
You should never call an HOC during the render phase because creating React components can be expensive. You should rather call these wrappers at initialization.
Note that when using functional components like above, the HOC version do not provide any useful optimisation because stateless functional components do not implement shouldComponentUpdate
More explanations here: https://stackoverflow.com/a/31564812/82609
const ParentComponent = (props) => {
return(
{props.childComponent}
//...additional JSX...
)
}
//import component
import MyComponent from //...where ever
//place in var
const myComponent = <MyComponent />
//pass as prop
<ParentComponent childComponent={myComponent} />
You can pass it as a normal prop: foo={<ComponentOne />}
For example:
const ComponentOne = () => <div>Hello world!</div>
const ComponentTwo = () => (
<div>
<div>Hola el mundo!</div>
<ComponentThree foo={<ComponentOne />} />
</div>
)
const ComponentThree = ({ foo }) => <div>{foo}</div>
Facebook recommends stateless component usage
Source: https://web.archive.org/web/20160608001717/http://facebook.github.io/react/docs/reusable-components.html
In an ideal world, most of your components would be stateless
functions because in the future we’ll also be able to make performance
optimizations specific to these components by avoiding unnecessary
checks and memory allocations. This is the recommended pattern, when
possible.
function Label(props){
return <span>{props.label}</span>;
}
function Hello(props){
return <div>{props.label}{props.name}</div>;
}
var hello = Hello({name:"Joe", label:Label({label:"I am "})});
ReactDOM.render(hello,mountNode);
i prefer using React built-in API:
import React, {cloneElement, Component} from "react";
import PropTypes from "prop-types";
export class Test extends Component {
render() {
const {children, wrapper} = this.props;
return (
cloneElement(wrapper, {
...wrapper.props,
children
})
);
}
}
Test.propTypes = {
wrapper: PropTypes.element,
// ... other props
};
Test.defaultProps = {
wrapper: <div/>,
// ... other props
};
then you can replace the wrapper div with what ever you want:
<Test wrapper={<span className="LOL"/>}>
<div>child1</div>
<div>child2</div>
</Test>
You can pass in a component via. the props and render it with interpolation.
var DivWrapper = React.createClass({
render: function() {
return <div>{ this.props.child }</div>;
}
});
You would then pass in a prop called child, which would be a React component.
Late to the game, but here's a powerful HOC pattern for overriding a component by providing it as a prop. It's simple and elegant.
Suppose MyComponent renders a fictional A component but you want to allow for a custom override of A, in this example B, which wraps A in a <div>...</div> and also appends "!" to the text prop:
import A from 'fictional-tooltip';
const MyComponent = props => (
<props.A text="World">Hello</props.A>
);
MyComponent.defaultProps = { A };
const B = props => (
<div><A {...props} text={props.text + '!'}></div>
);
ReactDOM.render(<MyComponent A={B}/>);
Actually, your question is how to write a Higher Order Component (HOC). The main goal of using HOC is preventing copy-pasting. You can write your HOC as a purely functional component or as a class here is an example:
class Child extends Component {
render() {
return (
<div>
Child
</div>
);
}
}
If you want to write your parent component as a class-based component:
class Parent extends Component {
render() {
return (
<div>
{this.props.children}
</div>
);
}
}
If you want to write your parent as a functional component:
const Parent = props => {
return (
<div>
{props.children}
</div>
);
}
Here is an example of a parent List react component and whos props contain a react element. In this case, just a single Link react component is passed in (as seen in the dom render).
class Link extends React.Component {
constructor(props){
super(props);
}
render(){
return (
<div>
<p>{this.props.name}</p>
</div>
);
}
}
class List extends React.Component {
render(){
return(
<div>
{this.props.element}
{this.props.element}
</div>
);
}
}
ReactDOM.render(
<List element = {<Link name = "working"/>}/>,
document.getElementById('root')
);
Let's create a Wrapper Component:
export const Wrapper = (props) => {
return(<>
<Menu />
{props.children}
<Footer />
</>
)
}
You can now enclose your new into an existing structure.
You will enclose the Component in a Route for example:
<Route path="/" element={<Wrapper><ExampleComponent /></Wrapper>} />
You can pass your component as a prop and use the same way you would use a component.
function General(props) {
...
return (<props.substitute a={A} b={B} />);
}
function SpecificA(props) { ... }
function SpecificB(props) { ... }
<General substitute=SpecificA />
<General substitute=SpecificB />
you can pass your react component into another component and emit the function from child
import CustomerFilters;
parent:
const handleFilterChange = (value) => {
console.log(value)
}
<DataGrid
contentName="customer"
fetchFilterComponents = {<CustomerFilters onSelectFilter={handleFilterChange} />}
</DataGrid>
child:
CustomerFilters
return (
<select className="filters-dropdown" onChange={onSelectFilter}>
<option>Select Filter</option>
{customerFilterOptions?.map((filter: any) => {
return <option value={filter.value}>{filter.name}</option>;
})}
</select>
)