Convert functional component from class component - reactjs

I want to convert my class component to functional component and t is difficult for me to convert render() of class component.
Here is my code sandbox link. https://codesandbox.io/s/snowy-smoke-s65vx4?file=/src/App.js
Can anyone please help me with this

The render part is just going to be the body of the function and the return.
const myfunccomp : React.FC = ({id, info, msgList}) => {
const chatContentHeader = () => {...}
const chatContentBody = () => {...}
const chatContentFooter = () => {...}
...
return (
<div className="chat-content">
{chatContentHeader(info.name)}
{chatContentBody(msgList, id)}
{chatContentFooter()}
</div>
);
}

Related

Passing object to child component loses its properties and methods

I have App.js that has a component in it where I pass down props:
let chess = new Chess();
// lots of code...
console.log("chess in App.js", chess);
return <ChildComponent chess={chess} />;
The ChildComponent.js receives this prop as follows:
const ChildComponent = (chess) => {
console.log("chess", chess);
};
When I inspect that in Chrome, I get this:
So, I am somehow losing the object detail when I pass it down as props. Is there something obvious that I am doing wrong?
It needs to be in a {} because it's inside a props object
const ChildComponent = ({ chess }) => {
console.log("chess", chess);
};
OR
const ChildComponent = (props) => {
console.log("chess", props.chess);
};
Your code, log the props object,
try this
const ChildComponent = (props) => {
console.log('chess', props.chess)
}
or
const ChildComponent = ({chess}) => {
console.log('chess', chess)
}

How redux action dispatch differ between class & function component?

I would like to know how redux implementation in functional component different from class component.
Because I got a working example and not working example.
The working example is the class component. When I use class component and use props.fetchSomething
Its always works.
here is the class component.
import React, { Component } from "react";
class Posts extends Component {
componentDidMount() {
this.props.fetchPosts();
}
render() {
let postItems = this.props.posts.map((post) => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>
));
return <div>{postItems}</div>;
}
}
Now I will show you the not working version of function component.
import React, { useEffect } from "react";
const Posts = ({ fetchPosts, posts }) => {
useEffect(() => {
fetchPosts();
}, []);
let items = posts.map((post) => {
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>;
});
return <div>{items}</div>;
};
As you can see, FROM MY UNDERSTANDING these 2 works the same, Because i fetch the data at mounting state and map the store data.
Here my rest of the code. which are redux operations. I used these below codes for both class and function component. The thing is, only the class component show the list of data. The function component always return an empty array.
WHY IS THAT
Posts.propTypes = {
fetchPosts: PropTypes.func.isRequired,
posts: PropTypes.array.isRequired,
newPost: PropTypes.object,
};
const mapStateToProps = (state) => ({
// coming from root reducer
posts: state.posts.itemsArray,
newPost: state.posts.item,
});
export default connect(mapStateToProps, { fetchPosts })(Posts);
Items is not assigned to anything because the callback function passed to map doesn't return anything:
useEffect(() => {
fetchPosts();
//you should really try using create-react app, then
// you'd see the missing dependency when compiling
// When you also set up vs code you'd see it when you
// open the file in the editor
}, [fetchPosts]);
//in VS code you would have a linter warning:
// Expected to return a value in arrow function.
// also defined items as const
const items = posts.map((post) => (//replaced { with (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>//removed ;
)/**replaced } with ) */);
If you use {...} after the arrow of an arrow function then ... is the body of the function and you have to return something from this body:
let items = posts.map((post) => {
return (//have to return jsx
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>
); //removed ;
});
You can also have an arrow function that has no body, then whatever comes after the arrow is the return value. For example: const add = (a,b)=>a+b.
If you have a bodyless arrow function that returns an object it gets confusing because an object and a function body have the same syntax {} so to return an object you can do ({}), here is an example: const add = (a,b)=>({sumAB:a+b}). With jsx the (<jsx />) are optional so const hello = () => <div>hello</div>; and const hello = () => (<div>hello</div>); are both valid. When multi line jsx is returned a formatter such as prettier will usually format it with (<jsx />) like so:
const hello = () => (
<div>
<div>hello</div>
</div>
);

Attach a property to a functional component wrapped with React.forwardRef

I have a component wrapped with React.forwardRef and it so happens that it is a compound component as well.
I'm not sure how do I maintain
Form.Item = FormItem;
while the Form component function being wrapped with forwardRef.
const Form = React.forwardRef((props, ref) => { return <form></form>});
Typescript gives me an error (rigthly) saying
Property 'Item' does not exist on type 'ForwardRefExoticComponent>'.ts(2339)
Just to make it more clear of the solution, as it's on an external site (Credits to original author here, and thank you #Antoan Elenkov)
export interface Props = {
...yourPropsHere;
};
export interface CompoundedComponent extends React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLInputElement>> {
yourStaticFunctionOrSomethingLikeThat: () => void;
}
const Component = React.forwardRef<HTMLInputElement, Props>((props, ref) => (
<input ref={ref} {...props} />
)) as CompoundedComponent;
Component.yourStaticFunctionOrSomethingLikeThat = () => {};
This solution from the same GH thread seems nicer to me:
const Form = React.forwardRef(function Form(...) {
...
})
const FormItem = React.forwardRef(...)
const FormNamespace = Object.assign(Form, {Item: FormItem})
export {FormNamespace as Form}

Unable to update the text using useState

I am converting a class based component to a functional component
But in functional component state is not getting updated.
Could you please update what might be the issue.
I tried putting a alert & its working
I have converted previously working below code-base :
class Spice extends React.Component {
constructor() {
super();
this.state = {
title: 'Welcome to XYZ '
};
}
nameChangeFunction() {
this.setState({
title: 'Welcome to Authentic XYZ World'
});
}
And the Calling Snippet:
render() {
const spiceList = [
..,
..,
..
];
return (
<div>
<h1>{this.state.title}</h1>
<button className='tc ma5' onClick={() => this.nameChangeFunction()}>
Check Out
</button>
<br />
</div>
);
}
New functional component is created as below, but its not updating the title, onClick.
const SpiceHookBased = () => {
const [title, setTitle] = useState("INITIAL XYZ Title");
const changeTitle = () => {
return setTitle("some value changed");
}
return {
render() {
const spiceList = [
..,
..,
..
];
return (
<div>
<h1>{title}</h1>
<button className='tc ma5' onClick={changeTitle}>
</button>
);
}
}
}
In second case, its not updating new text title.
Kindly suggest a correction
Thanks
In the codesnippet there was multiple return and render. See the below codesnippet and check
Apart from that the code looks fine, you can remove the return and write it in a single line
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const App = () => {
const [title, setTitle] = useState("INITIAL XYZ Title");
const changeTitle = () => setTitle("some value changed")
return (
<div>
<h1>{title}</h1>
<button className="tc ma5" onClick={changeTitle}>
Click Me to change title
</button>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Working codesandbox
You don't need to return the setTitle function in your update function.
Also there is no need for the render() method in functional components, when you return an object like you are doing it just turns the component into a regular function, not a react Component, so that is likely the reason your useState hooks aren't working.
Try changing your functional component to this:
const SpiceHookBased = () => {
const [title, setTitle] = useState("INITIAL XYZ Title");
const changeTitle = () => {
setTitle("some value changed");
}
return (
<div>
<h1>{title}</h1>
<button className='tc ma5' onClick={changeTitle}>
</button>
);
}
EDIT: I saw on another answer you said you are using this component elsewhere which "does the final job of rendering". That is the problem, you are essentially trying to use this component as a function, which doesn't understand react hooks, and thats why the hooks aren't working. If you want to use that type of pattern you need to return a new Component with any added props that you need.

React onComponentDidMount event with react-redux connect

In the below example, onComponentDidMount does not work because that event does not exist in React. Assuming I don't want to rewrite Main using React.Component, what event should I use, or is there another way?
let Main = ({myEventMethod}) => (
<main onComponentDidMount={myEventMethod}>
...
</main>
)
const mapDispatchToProps = (dispatch) => ({
myEventMethod: () => {...}
})
Main = connect(null, mapDispatchToProps)(Main)
DOCS:
Stateless Functions do not have the component lifecycle methods.
Higher Order Components come to rescue. Demo.
const withComponentDidMount = handler => Cmp => {
class WithComponentDidMount extends Component {
render() {
return <Cmp {...this.props}/>
}
}
WithComponentDidMount.prototype.componentDidMount = handler
return WithComponentDidMount
}
const Wrapped = withComponentDidMount(function() {
console.log('Mount')
})(App)

Resources