React | ForwardedRef using React.Component - javascript

I'm creating a custom component in React, and I need to export it using forwardedRef. But when I try, this error occurs:
error
my code:
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>{
ref?: React.RefObject<HTMLButtonElement>;
}
class Button extends React.Component<ButtonProps> {
render() {
const {
ref,
children,
...otherProps
} = this.props;
return (
<button
{...otherProps}
ref={ref}
>
{children}
</button>
)
}
}
const ButtonForwarded = React.forwardRef<ButtonProps>((props, ref) =>
<Button {...props} ref={ref} /> );
ButtonForwarded.displayName = 'Button';
export default ButtonForwarded;

Create the ButtonForwarded component like this:
const ButtonForwarded = React.forwardRef((props: ButtonProps, ref: LegacyRef<Button>) => <Button {...props} ref={ref} /> );

Related

how to change child component state in reactjs

I came across the following problem: I need to use another component's function inside a component:
header.js
export default function Header() {
const [showModalLogin ,setShowModalLogin] = useState(false);
return(
<>
<span>Hi, <Link onClick={() =>{ setShowModalLogin(true)}}>login</Link> </span>
{showModalLogin ? <LoginModal setShowModalLogin={setShowModalLogin}/> : ''}
</>
);
}
home.js
import Header from '../../components/header/header';
export default function Home() {
return (
<>
<Header />
<Link onClick={() =>{ setShowModalLogin(true)}}>open login</Link>
</>
}
How do I do in home.js to call the setShowModalLogin function that is in header.js ? I'm trying to use the context api too, but I still can't solve it.
You can just place useState in Header component and pass setShowModalLogin as props:
import Header from '../../components/header/header';
export default function Home() {
const [isShowModalLogin ,setShowModalLogin] = useState(false);
return (
<>
<Header isShowModalLogin={isShowModalLogin} setShowModalLogin={setShowModalLogin} />
<Link onClick={() => setShowModalLogin(true)}>open login</Link>
</>
}
export default function Header({ isShowModalLogin, setShowModalLogin }) {
return(
<>
<span>Hi, <Link onClick={() => setShowModalLogin(true)}>login</Link> </span>
{isShowModalLogin ? <LoginModal setShowModalLogin={setShowModalLogin}/> : ''}
</>
);
}
Then you can do it in this way:
Create Context
Save useState inside
Use it everywhere you need
export const YourContext = createContext();
export const YourProvider = ({ children }) => {
const [isShowModalLogin, setShowModalLogin] = useState(false);
const value = {
isShowModalLogin,
setShowModalLogin
};
return <YourContext.Provider value={value}>{children}</YourContext.Provider>;
}
// App.js
const App = () => {
return (
<YourProvider>
<AppContent />
</YourProvider>
)
}
So now you can use it like here:
import Header from '../../components/header/header';
export default function Home() {
const { isShowModalLogin, setShowModalLogin } = useContext(YourContext);
return (
<>
<Header isShowModalLogin={isShowModalLogin} setShowModalLogin={setShowModalLogin} />
<Link onClick={() => setShowModalLogin(true)}>open login</Link>
</>
}

Something went wrong!Element type is invalid: expected a string (for built-in components) or a class/function For HOC

import React, { useState } from 'react';
import CreateProject from './CreateProjectWithName';
function Enhanced(WrappedComponent) {
// ...and returns another component...
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
render() {
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
}
const Wrapper = (props) => {
const Comp = Enhanced(<CreateProject />);
return (
<div>
<Comp />
<div>
{/* <button onClick={() => updateView()} /> */}
</div>
</div>
);
};
This code block just won't work. What am I doing wrong? Which principal fundamental of React am I missing out on? What is the correct way of rendering an HOC?
The HOC takes in a component reference what you are providing it is an instance when you use it like
const Comp = Enhanced(<CreateProject />);
The correct way would be
const Comp = Enhanced(CreateProject);
Also for performance reasons and for proper execution of lifecycle you must create a wrapped component with HOC outside of your component
const Comp = Enhanced(CreateProject);
const Wrapper = (props) => {
return (
<div>
<Comp />
<div>
{/* <button onClick={() => updateView()} /> */}
</div>
</div>
);
};
function Enhanced(WrappedComponent) {
// ...and returns another component...
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
render() {
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
}
const Wrapper = (props) => {
const Comp = Enhanced(CreateProject );
return (
<div>
<Comp />
<div>
{/* <button onClick={() => updateView()} /> */}
</div>
</div>
);
};

How can I pass a ref to HOC that uses onClickOutside('react-onclickoutside')?

I use onClickOutside('react-onclickoutside') for my HOC and I can't pass ref for this HOC, I have something like below and an error appears:
const inputRef = useRef();
....
<SomeCompontnt
inputRef={inputRef}
items={items}
onSelect={onSelect}
value={selectedItem}
/>
....
export default onClickOutside(forwardRef(
(props, inputRef) => <MyHoc inputRef={inputRef} {...props} />)
);
....
Errors
Uncaught TypeError: Cannot read property 'isReactComponent' of
undefined
at onClickOutside.render (react-onclickoutside.es.js?7e48:325)
try this:
you can see MyHoc onClick output in OnclickoutsideDemo MyHookClick console
import React from "react";
import { render } from "react-dom";
import onClickOutside from "react-onclickoutside";
class OnclickoutsideDemo extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
const options = this.state.showOptions ? (
<MyHookClick
onClick={e => console.log(e)}
handleClickOutside={() => this.setState({ showOptions: false })}
/>
) : null;
return (
<div>
<span
onClick={() =>
this.setState({ showOptions: !this.state.showOptions })
}
>
Click Me
</span>
{options}
</div>
);
}
}
const MyHoc = React.forwardRef((props, ref) => (
<div ref={ref} onClick={e => props.onClick("HaHa")}>
Click Me to see HaHa in console !
</div>
));
const MyHookClick = onClickOutside(props => (
<MyHoc ref={props.inputRef} {...props} />
));
export default OnclickoutsideDemo;
render(<OnclickoutsideDemo />, document.getElementById("root"));

"this.context" returns an empty object

I can't figure out why:
I have react _ react-dom 16.8x
I have a component between my Provider and my Consumer to avoid cyclic call between the two aforementioned elements.
I would my context be accessible directly in lifecycle component and seen ReactJS propose the this.context's method to do that.
Here my sandbox
Here my reactjs snippet
import React, {Component}from "react";
import "./App.css";
// first we will make a new context
const MyContext = React.createContext();
// Then create a provider Component
class MyProvider extends Component {
state = {
name: 'Wes',
age: 100,
cool: true
}
render() {
return (
<MyContext.Provider value={{
state: this.state,
growAYearOlder: () => this.setState({
age: this.state.age + 1
})
}}>
{this.props.children}
</MyContext.Provider>
)
}
}
const Family = (props) => (
<div className="family">
<Person />
</div>
)
class Person extends Component {
componentDidMount(){
console.log("context: ", this.context)
}
render() {
console.log("context: ", this.context)
return (
<div className="person">
<MyContext.Consumer>
{(context) => (
<React.Fragment>
<p>Age: {context.state.age}</p>
<p>Name: {context.state.name}</p>
<button onClick={context.growAYearOlder}>🍰🍥🎂</button>
</React.Fragment>
)}
</MyContext.Consumer>
</div>
)
}
}
class App extends Component {
render() {
return (
<MyProvider>
<div>
<p>I am the app</p>
<Family />
</div>
</MyProvider>
);
}
}
export default App;
Why this.context is empty?
Any hint would be great,
thanks
You need to set contextType to consume a context.
On the react website it specifies as much anyway.
So the only change required:
class Person extends Component {
componentDidMount(){
console.log("context: ", this.context)
}
render() {
console.log("context: ", this.context)
return (
<div className="person">
<MyContext.Consumer>
{(context) => (
<React.Fragment>
<p>Age: {context.state.age}</p>
<p>Name: {context.state.name}</p>
<button onClick={context.growAYearOlder}>🍰🍥🎂</button>
</React.Fragment>
)}
</MyContext.Consumer>
</div>
)
}
}
Person.contextType = MyContext;
Hope this helps!
If you need access to MyContext in Person, you can wrap Person in the consumer and pass in context when you render it in Family:
const Family = (props) => (
<div className="family">
<MyContext.Consumer>
{(context) => {
<Person context={context} />
}}
</MyContext.Consumer>
</div>
)
class Person extends Component {
componentDidMount(){
console.log("context: ", this.props.context)
}
render() {
const { context } = this.props;
console.log("context: ", context)
return (
<div className="person">
<React.Fragment>
<p>Age: {context.state.age}</p>
<p>Name: {context.state.name}</p>
<button onClick={context.growAYearOlder}>🍰🍥🎂</button>
</React.Fragment>
</div>
)
}
}

How to get data from react context

I have a React class called GlobalDataProvider:
import React, { Component } from 'react';
const DataContext = React.createContext();
export default DataContext;
export class DataProvider extends Component {
state = {
title: 'Some title'
}
render() {
return (
<DataContext.Provider
value={{state: this.state}}>
{this.props.children}
</DataContext.Provider>
)}
}
And I am trying to use data in another file "PageSection.js" like this:
import React from 'react';
import DataContext from '../data/GlobalDataProvider';
const PageSection= () =>{
return (
<section className="page-section">
<DataContext.Consumer>
{(context) => (
<h1>{ context.state.title }</h1>
)}
</DataContext.Consumer>
</section>
);
};
However this does not work for some reason. I get this error message:
TypeError: Cannot read property 'state' of undefined,
in PageSection.js line 11 (the line with this code: { context.state.title }).
What am I doing wrong?
Do I have to import the class DataProvider? or only the Context variable?
I suspect you need your DataContext.Consumer to be a child element of the DataContext.Provider. Something like this...
import React from 'react';
import DataContext, { DataProvider } from '../data/GlobalDataProvider';
const PageSection= () =>{
return (
<section className="page-section">
<DataProvider>
<DataContext.Consumer>
{(context) => (
<h1>{ context.state.title }</h1>
)}
</DataContext.Consumer>
</DataProvider>
</section>
);
};
try:
export class DataProvider extends Component {
state = {
title: 'Some title'
}
render() {
return (
<DataContext.Provider
value={this.state}>
{this.props.children}
</DataContext.Provider>
)}
}
const PageSection= () =>{
return (
<DataProvider>
<section className="page-section">
<DataContext.Consumer>
{(context) => (
<h1>{ context.title }</h1>
)}
</DataContext.Consumer>
</section>
</DataProvider>
);
};

Categories

Resources