How to properly create and render functional components? - javascript

I am attempting to create and render a functional component using the instructions here as a base. From what I've sen in there I should be able to do something along the lines of:
class MyComponent extends React.Component {
render() {
return (
<div>
<OtherComponent props="test" />
</div>
)}
function OtherComponent(props) {
return (
<div>
test
</div>
);
}
}
But this throws the error:
Unexpected token: function OtherComponent(props) {
^
I found a few posts that suggested removing the function so I tried that but then it throws the error:
OtherComponent is not defined
I'm able to get it working by creating a separate class component like so:
class OtherComponent extends React.Component {
render() {
But that's not what I want to do. What is the proper way to create/render a functional component in React.js?

For example this one works. See the docs ;)
React - Composing Components
function OtherComponent(props) {
return <div>test</div>;
}
class App extends React.Component {
render() {
return (
<div>
<OtherComponent props="test" />
</div>
);
}
}

Try this
class MyComponent extends React.Component {
OtherComponent = (props) => {
return (
<div>
test
</div>
);
}
render() {
return (
<div>
{this.OtherComponent("test")}
</div>
)}
}

You can't define a component inside of another component. A functional component means that the component is created from a function and is not a class. It can't have it's own state, because the state is initialized in class constructor. Check out this article for more info https://hackernoon.com/react-stateless-functional-components-nine-wins-you-might-have-overlooked-997b0d933dbc
const otherComponent = (props) =>
<div>
test
</div>;

Here is another way. Its not correct to declare a component in a render function. If it is used solely in a parent component why not make that explicit and use static
class MyComponent extends React.Component {
static myOtherComponent = (props) => <div>{'test'}</div>
render(){
return(
<div>
<MyComponent.myOtherComponent {props} />
</div>
)
}
The myOtherComponent behaviour is controlled purely through the props it gets , it won't have its own state.
Or you could just make it a separate component e.g
export default myOtherComponent = (props) => ()
and import it into MyComponent. Please note , now with hooks ( see React Docs ), you can use hooks to mimic state etc in functional components and the latter approach might be your cleanest and most flexible approach.

This way you can define a function component
function OtherComponent(props) {
return <div>{props}</div>;
}
And now you can use functional component in your App (class component) like below
class App extends React.Component {
render() {
return (
<div>
<OtherComponent props="test" />
</div>
);
}
}

Related

React anti pattern?

Is the following an anti pattern in React? I like the pattern because it gives me context in static functions when a component has been instantiated. Then later I can import the class and call a static method to modify state. Or can this be done in a better way?
// componentA.js
function bleedContext() {
ComponentA.staticMethod = ComponentA.staticMethod.bind(this)
}
export default class ComponentA {
static staticMethod() {
this.setState({foo: 'bar'})
}
constructor() {
this.state = {}
bleedContext.call(this)
}
render() {
return (
...
)
}
}
// componentB.js
import ComponentA from 'path/to/componentA'
export default class ComponentB {
handleClick() {
ComponentA.staticMethod()
}
render() {
return (
<button onClick={this.handleClick} />
)
}
}
This is clearly an antipattern and possibly a mistake, depending on conditions. Static class method shouldn't operate with class instance. staticMethod is bound to specific component instance and uses setState, this could be only justified a class is a singleton (though a singleton is often an antipattern, too). This will result in bugs and memory leaks if more than one class instance is expected, and every React component is expected to have more than one instance, at least for testing.
A proper way for two independent components to interact with each other in React is to have a common parent component that provides this interaction, e.g.:
class ModalContainer extends Component {
modalRef = React.createRef();
render() {
return <>
<Modal ref={this.modalRef} />
<SomeComponentThatUsesModal modalRef={this.modalRef} />
</>;
}
}
The problem with example above is that this will require to pass modalRef prop deeply if <SomeComponentThatUsesModal> is nested.
This problem is solved with React context or other third-party global state solutions like Redux.
This can be done with React 16.3 context API, considering that Modal class instance has open method:
const ModalContext = React.createContext();
function getModal(modalRef) {
return {
open: data => modalRef.current.open(data);
close: () => modalRef.current.close();
}
}
class ModalContainer extends Component {
modalRef = React.createRef();
render() {
return <>
<Modal ref={this.modalRef} />
<ModalContext.Provider value={getModal(this.modalRef)}>
{this.props.children}
</ModalContext.Provider>
</>;
}
}
Then for any deeply nested component modal object with open and close methods will be available via context:
const SomeComponentThatUsesModal = props => <div>
<ModalContext.Consumer>
{modal => <button onClick={() => modal.open('foo')} />}
</ModalContext.Consumer>
</div>;
<ModalContainer>
...deeply nested component
<SomeComponentThatUsesModal />
...
</ModalContainer>
Here's a demo.

call child function from parent in reactjs

My parent component
import EditReview from './partials/editReview'
class VenueDetails extends Component {
constructor(props) {
super(props)
this.child = React.createRef();
}
render() {
return (
<div className="place-review-text">
<EditReview {...this.props}/>
</div>
)
}
}
My child component
class EditReview extends Component {
onEditClick(review, editIndex) {
console.log('ppp')
}
render() {
const { handleSubmit, user, pristine, index, commentCrossClick } = this.props
return (
<div>
<Field
name="content"
component={renderTextArea}
className="form-control"
label="Write your review..."
rows={2}
/>
</div>
)
}
}
export default EditReview
I need to call onEditClick from the parent component. I tried this but doesn't work.
Kindly help me
Edit
After upgrade I am getting this
Error in ./~/react-dom/lib/ReactServerRendering.js
Module not found: 'react/lib/React' in /home/user/ashish/LTC/lovethesecities-frontend/node_modules/react-dom/lib
After resolving all the errors call child function from parent in react 16
React docs have a example of this using refs
https://reactjs.org/docs/refs-and-the-dom.html
I’m also wondering the use case of wanting to do this, maybe some context could help with an answer?
Try doing it like this:
import EditReview from './partials/editReview'
class VenueDetails extends Component {
render() {
return (
<div className="place-review-text">
<EditReview ref={Ref => this.child=Ref } {...this.props} />
</div>
)
}
}
and call the function in parent component as this.child.onEditClick(param1,param2)
EDIT1:
if you have to do it with react 15.x itself what you can do it is create the function in parent and pass it as a prop to child

Functions are not valid as a React child. This may happen if you return a Component instead of from render

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.

react: uncaught TypeError: Cannot read property 'state' of undefined

I am trying to get 'state' object in function Application which is out from General class and I am getting this error "Uncaught TypeError: Cannot read property 'state' of undefined".
The code is
class General extends Comment {
constructor() {
super();
this.state = { comments: first_comment};
}
}
const Application = () => {
return (
<div> Hello world beginner: {this.state.comments}</div>
);
};
render(<Application/>, document.getElementById('container'));
Application is stateless component. Not to say that arrow functions have lexical scoping of context.
Use props for stateless components.
const Application = (props) => {
return (
<div> Hello world beginner: {props.comments}</div>
);
};
Or extend React.Component
class Application extends React.Component {
constructor() {
// init state
}
render() {
return <div> Hello world beginner: {this.state.comments}</div>
}
}
Few Things:
*Stateless Functional Components don't have state, lifecycle methods, and this keyword.
*You need to connect General and Application component so that Application component can you the state value of General component.
*Make Application component as child of General component and pass the comments value in props, and in Application access the value by props.comments.
Write it like this:
class General extends Component {
constructor() {
super();
this.state = { comments: first_comment};
}
render(){
return (
<div>
<Application comments={this.state.comments}/>
</div>
)
}
}
const Application = (props) => {
return (
<div> Hello world beginner: {props.comments}</div>
);
};
render(<General/>, document.getElementById('container'));
Check the working example:
class General extends React.Component {
constructor() {
super();
this.state = { comments: 'first_comment'};
}
render(){
return (
<div>
<Application comments={this.state.comments}/>
</div>
)
}
}
const Application = (props) => {
return (
<div> Hello world beginner: {props.comments}</div>
);
};
ReactDOM.render(<General/>, document.getElementById('container'));
<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='container'/>
In your class component you should be extending or subclassing React.Component and when you do, that means you are going to be overriding the constructor() functions of React.Component classes with the one from General class-component, but you don't want to do that, you still want to access React.Component constructor() so you need to pass in props to the constructor and to super().
Next, when passing state as props to a functional component, you need to pass in props as an argument to the functional component, otherwise when doing this for example:
import React from 'react';
const ImageList = () => {
console.log(props.images);
return <div>ImageList</div>;
};
export default ImageList;
you will get that same error you got. Imagine I am trying to access state from your General class-based component into this ImageList component above and I do have it imported to General, it will give me the same error, because I have not passed props as an argument to ImageList functional component.

Reactjs:Is it possible to use Parent component property from another Parent's child component

I have a file named separatefile.jsx, in this file parent component name is Content and child component name is Child.
separatefile.jsx
import React from 'react';
import Parent from './learning.jsx';
class Content extends React.Component {
constructor() {
super();
this.state = {
finding : 'i am finding'
}
}
render() {
return (
<div>
<Child childprop={this.state.finding}/>
<Parent/>
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
<h2>{this.props.childprop}</h2>
<h1>child class property</h1>
</div>
);
}
}
export default Content;
This is another file named as learning.jsx , this file has Parent component named as Parent and Child component named as a Children.
My questions is that i need to access Parent component property(parent component for learning.jsx) from Child component(child component for separatefile.jsx file)...
learning.jsx
import React from 'react';
class Parent extends React.Component {
constructor() {
super();
this.state = {
searching : 'i will find the solution'
}
}
render() {
return (
<div>
<Children childrenprop={this.state.searching}/>
</div>
);
}
}
class Children extends React.Component {
render() {
return (
<div>
<h2>{this.props.childrenprop}</h2>
</div>
);
}
}
export default Parent;
If I understood you correctly, you want to use Parent's state in your Children component?
You can pass it down the component tree as props, e.g.:
class Content extends React.Component {
constructor() {
super();
this.state = {
finding : 'i am finding'
}
}
render() {
return (
<div>
<Child childprop={this.state.finding}/>
<Parent finding={this.state.finding} />
</div>
);
}
}
class Parent extends React.Component {
constructor() {
super();
this.state = {
searching : 'i will find the solution'
}
}
render() {
return (
<div>
<Children finding={this.props.finding} childrenprop={this.state.searching}/>
</div>
);
}
}
class Children extends React.Component {
render() {
return (
<div>
<h2>{this.props.childrenprop}</h2>
<div>{this.props.finding}</div>
</div>
);
}
}
It's probably not a direct answer but if you are starting a new app I would recommend you to use Redux with react-redux.
Redux is a predictable state container for JavaScript apps.
It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.
It's very small library so it's easy to understand how everything works. It might be a good solution to your problem.
Todo app example
You can also check out awesome egghead.io free tutorial - Getting Started with Redux
Here is the answer about the redux benefits by its author Dan Abramov
The React documentation provides an answer.
For communication between two components that don't have a
parent-child relationship, you can set up your own global event
system. Subscribe to events in componentDidMount(), unsubscribe in
componentWillUnmount(), and call setState() when you receive an event.
Flux pattern is one of the possible ways to arrange this.

Categories

Resources