Can i pass component state to HoC? - javascript

Is there any way to send data from the component's state to HoC?
My component
import React, { Component } from 'react';
import withHandleError from './withHandleError';
class SendScreen extends Component {
contructor() {
super();
this.state = {
error: true
}
}
render() {
return (
<div> Test </div>
)
}
};
export default withHandleError(SendScreen)
My HoC component:
import React, { Component } from 'react';
import { ErrorScreen } from '../../ErrorScreen';
import { View } from 'react-native';
export default Cmp => {
return class extends Component {
render() {
const { ...rest } = this.props;
console.log(this.state.error) //// Cannot read property 'error' of null
if (error) {
return <ErrorScreen />
}
return <Cmp { ...rest } />
}
}
}
Is there any way to do this?
Is the only option is to provide props that must come to the SendScreen component from outside??

A parent isn't aware of child's state. While it can get an instance of a child with a ref and access state, it can't watch on state updates, the necessity to do this indicates design problem.
This is the case for lifting up the state. A parent needs to be notified that there was an error:
export default Cmp => {
return class extends Component {
this.state = {
error: false
}
onError() = () => this.setState({ error: true });
render() {
if (error) {
return <ErrorScreen />
}
return <Cmp onError={this.onError} { ...this.props } />
}
}
}

export default withHandleError(data)(SendScreen)
In data you can send the value you want to pass to HOC, and can access as prop.

I know I answer late, but my answer can help other people
It is very easy to do.
WrappedComponent
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import HocComponent from './HocComponent';
const propTypes = {
passToHOC: PropTypes.func,
};
class WrappedComponent extends Component {
constructor(props) {
super(props);
this.state = {
error: true,
};
}
componentDidMount() {
const {passToHOC} = this.props;
const {error} = this.state;
passToHOC(error); // <--- pass the <<error>> to the HOC component
}
render() {
return <div> Test </div>;
}
}
WrappedComponent.propTypes = propTypes;
export default HocComponent(WrappedComponent);
HOC Component
import React, {Component} from 'react';
export default WrappedComponent => {
return class extends Component {
constructor() {
super();
this.state = {
error: false,
};
}
doAnything = error => {
console.log(error); //<-- <<error === true>> from child component
this.setState({error});
};
render() {
const {error} = this.state;
if (error) {
return <div> ***error*** passed successfully</div>;
}
return <WrappedComponent {...this.props} passToHOC={this.doAnything} />;
}
};
};
React docs: https://reactjs.org/docs/lifting-state-up.html

import React, { Component } from 'react';
import withHandleError from './withHandleError';
class SendScreen extends Component {
contructor() {
super();
this.state = {
error: true
}
}
render() {
return (
<div state={...this.state}> Test </div>
)
}
};
export default withHandleError(SendScreen)
You can pass the state as a prop in your component.

Related

React pass child class method to parent functional component

I am trying to get adaptValue from Component1 and use it in Component2. For some reason this does not work since my adaptValue is always null/undefined. Is it because Parent is a functional component?
const Parent = (props) => {
const [adaptValue, setAdapt] = useState(null);
return (
<div>
<Component1 setAdapt={setAdapt}/>
<Component2 adaptValue={adaptValue}/>
</div>
)
}
export default class Component1 extends Component {
constructor(props) {
super(props);
}
adaptValue = (value) =>{
DO_SOMETHING_WITH_VALUE
}
componentDidMount() {
this.props.setAdapt(this.adaptValue);
}
render() {
return something;
}
}
export default class Component2 extends Component {
constructor(props) {
super(props);
}
someFunction = (value) =>{
...
//adaptValue is always undefined
this.props.adaptValue(value)
...
}
render() {
return something;
}
}
UPDATE Made the parent a class component in the end and all works. Wondering whether this is a compatibility issue between functional or class-based components.
When passing setAdapt to Component1 ... setAdapt is already a function. There is no need to wrap it in another one. Component1 will modify the value, and Component2 will display it. Function Components have nothing to do with the behavior.
Try ...
App.js
import React, { useState } from "react";
import "./styles.css";
import Component1 from "./Component1";
import Component2 from "./Component2";
export default function App() {
const [adaptValue, setAdapt] = useState(null);
return (
<div>
<Component1 setAdapt={setAdapt} />
<Component2 adaptValue={adaptValue} />
</div>
);
}
Component1.js
import React, { Component } from "react";
export default class Component1 extends Component {
handleClick = () => {
this.props.setAdapt("New Value");
};
render() {
return <button onClick={() => this.handleClick()}>Set Value</button>;
}
}
Component2.js
import React, { Component } from "react";
export default class Component2 extends Component {
render() {
return !!this.props.adaptValue ? (
<h1>{`"${this.props.adaptValue}" <- Value of adaptValue`}</h1>
) : (
<h1>adaptValue Not Assigned</h1>
);
}
}
Sandbox Example ...

State is not passed down to child component

I have an issue in figuring in what conditions props are not passed down by the tree. I have a Fetcher class in which I populate with "layouts", then pass it to children props, but I cannot access it from child component.
EX:
import React, { Component } from 'react'
import axios from "axios";
export default class Fetcher extends Component {
constructor(props) {
super(props)
this.state = {
layouts: [],
}
componentDidMount() {
this.getLayouts();
}
getLayouts = () => {
axios
.get("/layout")
.then((res) => {
this.setState({
layouts: res.data,
});
})
.catch((err) => console.log(err));
};
render() {
return (
this.props.children(this.state.layouts)
)
}
}
This is my Parent component on which I pass some props children:
ex:
import React, { Fragment } from "react";
import Fetcher from "./Fetcher";
class App extends Component {
<Fetcher>
{(layouts) => {
return <Fragment>
<NewLayout
layoutsList={layouts} />
</Fragment>
}}
</Fetcher>
}
import React from "react";
class NewLayout extends React.Component {
constructor(props) {
super(props)
this.state = {
layouts: [],
}}
componentDidMount() {
this.setState(() => ({
layouts: this.props.layoutList
}))
}
render() {
{ console.log(this.state.layouts) }
{ console.log(this.props.layoutList) }
return (
....
The children prop is not a function, if you want to pass a property to it you should use React.Children API with React.cloneElement:
class Fetcher extends Component {
state = {
layouts: [/*some layout values*/],
};
render() {
const children = this.props.children;
const layouts = this.state.layouts;
return React.Children.map(children, (child) =>
React.cloneElement(child, { layouts })
);
}
}
Typo my friend, looks like you pass layoutsList prop to NewLayout, but internally use layoutList.

passing data from the parent component state to the child component using React.createContext

I have a component that contains a state, and I will pass the state data into another component, I use a static contextType to throw the state data but the data does not reach the intended component, what do you think this is wrong? thank you
this is my parent component
export const MyContext = React.createContext();
export class MerchantByPromo extends Component {
constructor(props) {
super(props);
this.state = {
dataPromo: [],
loading: true
};
}
async componentDidMount() {
const merchant_id = this.props.match.params.id_merchant
await Api.post('language/promo-voucher-by-merchant', { MERCHANT_ID: merchant_id })
.then((response) => {
if (response.data.STATUS_CODE === '200') {
this.setState({
dataPromo: response.data.DATA,
loading: false
});
}
})
}
this is my child component
import React, { Component } from 'react'
import { MyContext } from './MerchantByPromo'
export class MerchantByPromoDetail extends Component {
constructor(props){
super(props)
this.state = {
detailPromo:[],
}
}
UNSAFE_componentWillMount(){
let value = this.context
console.log(value)
}
componentDidMount(){
}
render() {
return (
<MyContext.Consumer>
<p>tes</p>
</MyContext.Consumer>
)
}
}
I always get an error message like this "TypeError: render is not a function", what's the solution?
<MyContext.Consumer>
{() => <p>tes</p>}
</MyContext.Consumer>
change to this and Check

How to change className?

So I keep div element in my state. I want to change it's className in response to onClick event. I know I could do it with event.target.className but the code below is only the sample of a biggest application and it's not possible to use it there. As a resultant from changeClass function I get
"TypeError: Cannot assign to read only property 'className' of object '#'".
So I wonder is there any other way to do it?
import React, { Component } from "react";
import "./styles/style.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
myDiv: [
<div
id="firstDiv"
key={1}
className={"first"}
onClick={this.changeClass}
/>
]
};
}
changeClass = () => {
this.setState(prevState => {
return { myDiv: (prevState.myDiv[0].props.className = "second") };
});
};
render() {
return <div>{this.state.myDiv.map(div => div)}</div>;
}
}
export default App;
Don't put your jsx in state. only add className and state and onChangeClass use this.stateState to update className.
import React, { Component } from "react";
import "./styles/style.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
className:"first"
};
}
changeClass = () => {
this.setState({ classNmae: "two" });
};
render() {
return <div>
<div
id="firstDiv"
className={this.state.className}
onClick={this.changeClass}
/>
</div>;
}
}
export default App;
there's a simpler option try this:
import React, { Component } from "react";
import "./styles/style.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
className: "first"
};
}
changeClass = () => {
this.setState({className: "second"});
};
render() {
return <div
id="firstDiv"
className={this.state.className}
onClick={this.changeClass}>
</div>;
}
}
export default App;
You can use Hooks if you use a React version upper than 16.8
import React, { useState } from "react"
import "./styles/style.css"
const App = () => {
const [myClass, setMyClass] = useState("first")
const changeClass = () => {
setMyClass("second")
}
render() {
return <div
id="firstDiv"
className={myClass}
onClick={changeClass}>
</div>;
}
}
export default App

higher order component can't see props

I'm using react with react-native and redux. The error comes to the component from the redux store. After that, i received: Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
What is wrong with this? why hoc can't see the props?
My component:
import React, { Component } from 'react';
import withHandleError from './withHandleError';
class SendScreen extends Component {
render() {
const { error } = this.props;
return (
<div> Test </div>
)
}
};
const mapStateToProps = ({ppm}) => ({
error: ppm.error
})
export default withHandleError(connect(mapStateToProps)(SendScreen));
And HoC:
import React, { Component } from 'react';
import { ErrorScreen } from '../../ErrorScreen';
import { View } from 'react-native';
export default Cmp => {
return class extends Component {
render() {
const {error, ...rest } = this.props;
console.log(error) //// undefined....
if (error) {
return <ErrorScreen />
}
return <Cmp { ...rest } />
}
}
}
The order is which you call the HOCs matters when you want to access props supplied by one in another. Re-ordering your connect and withHandleError HOC will work
import React, { Component } from 'react';
import withHandleError from './withHandleError';
class SendScreen extends Component {
render() {
const { error } = this.props;
return (
<div> Test </div>
)
}
};
const mapStateToProps = ({ppm}) => ({
error: ppm.error
})
export default connect(mapStateToProps)(withHandleError(SendScreen));

Categories

Resources