I'm trying to create a higher order component but keep getting this eslint waring.
component definition is missing display name
I tried adding a display name like below but it still complains.
import React from 'react';
const HOC = props => (WC) => {
WC.displayName = 'test'
return (
<WC />
);
}
export default HOC;
Two things you need to correct.
First: Fix order of your functional component declaration.
Second: setting displayName to the component returned from HOC
const HOC = WC => {
const MyComp = (props) => {
return (
<WC {...props} />
);
}
MyComp.displayName = 'test'
return MyComp;
}
Once you make the above change. You just need to use the HOC like
const MyCompWithHoc = HOC(CompA);
and render it like
<MyCompWithHoc propsA={'A'} {...otherPropsYouWantToPass} />
HOC is the component that's lacking a displayName property. The code you have above is changing the displayName property of WC which you don't want.
HOC.displayName = 'some higher component'
Your HOC should take the component as the first argument instead of props, see the example in the React docs: https://reactjs.org/docs/higher-order-components.html#convention-wrap-the-display-name-for-easy-debugging
EDIT: You can pass it props either by returning a functional component:
const HOC = WC => props => {
WC.displayName = 'test'
return (
<WC {...props} />
);
}
Or just return the wrapped component after setting the displayName:
const HOC = WC => {
WC.displayName = 'test';
return WC;
}
Related
Hi developers I'm just a beginner in React.js. I tried to print props by passing from parent to child.
This is app.js file
import React from "react";
import Hooks from "./components/ReactHooks1";
import Hooks2 from "./components/ReactHooks2";
const App = () => {
return (
<div>
<h1>
Welcome to React App
</h1>
<Hooks2 title2={"Welcome"}/>
</div>
)
}
export default App
This is child component file
import React from 'react';
const Hooks2 = (props) => {
console.log(props);
}
export default Hooks2;
I just try to print props but it shows an empty object. what am I doing wrong please help me on this
You should return something or null to parent component from child, when you're using it in parent component. This will solve your problem
export const Hooks2 = (props) => {
console.log(props);
return <></>;
}
#Rasith
Not sure why would you want to do this, but if you're trying to pass a child component that would print something to the console. In this case you need to destructure the component's props. Here's an article about it from MDN.
This is how I would do it:
const CustomComponent = ({title}) => {
console.log(title)
}
const App = () => {
return (
<>
<h1>Hello World</h1>
<CustomComponent title={"Welcome"}/>
</>
);
};
For the title to be printed to the console, no need to add a return statement to the child component. Again, not sure why you would do this, but there you go.
Well trying to console.log title certainly would not work because what you are passing is called title2. Also your child component is not returning anything.
First, you have to return anything from your child component( even a fragment )
You can access title2 in the child component with any of these methods:
1- using props object itself
const Hooks2 = (props) => {
console.log(props.title2);
return;
}
2- you can also destructure props in place to access title2 directly
const Hooks2 = ({title2}) => {
console.log(title2);
return ;
}
You have to use destructuring in your ChildComponent, to grab your props directly by name:
const Hooks2 = ({title2}) => {
console.log(title2);
}
You can read a little bit more about it in here: https://www.amitmerchant.com/always-destructure-your-component-props-in-react/
Lets say I have a wrapper component:
// wrapper that renders component passed as a prop
const Component = (childrenComponent) => <div>{childrenComponent}</div>
What I'd like to do is to invoke Component within some page, like:
import React from 'react'
const Page = () => {
const ChildrenComponent = () => <div>Children Component</div>
return <Component childrenComponent={ChildrenComponent} />
}
This will work well. My question is, given that prop names should be lowerCase, how can I change wrapper component code to be able to invoke ChildrenComponent in a JSX way (, instead of inline {childrenComponent}, while satisfying the requirement to name react components in PascalCase:
// this will not work
const Component = (childrenComponent) => <div><childrenComponent /></div>
// this will work but the prop name isn't camelCase
const Component = (ChildrenComponent) => <div><ChildrenComponent /></div>
You can setup Component like this:
const Component = props => {
return (
<div>{props.children}</div>
)
}
Using Component:
<Component>
<ChildrenComponent/>
</Component>
More reading material from the docs
You can use cloneElement as follows:
const Component = (children, ...props) => {
const clonedChild = cloneElement(children(), props)
return <>{clonedChild}</>
}
You need to wrap the returning result into a fragment.
I can't manage to pass props to my Outlet components in the new react-router v6. I tried the straightforward solution:
render() {
return (
<Outlet name="My name" />
);
}
And that correctly renders the child component, however no props are passed to the child. None of the examples provided by the React team (or anyone else for that matter) display Outlets with props, so I'm worried it's not actually a thing. Is there another way I'm not finding or am I using Output components incorrectly?
Edit: Seems there's no straightforward way to pass props, see answer below.
You can do it with
outlet context
This is now possible (from version 6.1.0) with the context prop
<Outlet context={}/>
github issue
react router outlet docs
An alternative option here is to use Context API to share props from your parent view to your child view.
const Context = React.createContext({})
function ParentView () {
const outlet = useOutlet()
return (
<Context.Provider value={{ foo: 'bar' }}>
<h1>Parent View</h1>
{outlet}
</Context.Provider>
)
}
function ChildView () {
const props = React.useContext(Context)
return (
<div>child view {props.foo}</div>
)
}
Another option (untested) may be to use React.cloneElement to clone outlet and add props to it.
When using functional component declare the name in the parent component like this.
function Parent() {
const const name='Your name'
return <Outlet context={[name]} />;
}
Then in the child component do this
//import this
import { useOutletContext } from "react-router-dom";
function Child() {
const [name] = useOutletContext();
return <p >{name}</p>;
}
one way i did it and it works well is to create a reach context, if you know how to use react context, this will be easy for you.
In a separate file create Context.js to prevent require loop
const AdminStoreContext = React.createContext();
and then export it
export{AdminStoreContext}
then in another file create a consumer and provider of the context, and then import the context you've creates
import { AdminStoreContext } from "../../contexts";
class AdminStoreContextProvider extends React.Component {
constructor(props) {
super(props);
this.state = { ===vlaues you want to share }
}
render() {
return (
<AdminStoreContext.Provider
value={{
...this.state,//===spread the value you want to share
}}>
{
this.props.children
}
</AdminStoreContext.Provider>
);
}
}
const AdminStoreContextConsumer = AdminStoreContext.Consumer;
export { AdminStoreContextConsumer, AdminStoreContextProvider }
you can wrap your app with the context
<AdminStoreContextProvider>
<app/>
<AdminStoreContextProvider />
you can use either the consumer or the context to get the values for the purpose of Outlet, we use the context
once again import it
import { AdminStoreContext } from "../../contexts";
const route[{
path: 'consumer',
element: <MyMainComponent AdminStoreContext ={AdminStoreContext } />,
children: [
{ path: 'account', element: <MySubComponent1 /> },
{ path: 'purchaseHistory', element: <MySubComponent2 /> }
]
},
then in your MySubComponent1 or MySubComponent2
get the value from the props and use
const { AdminStoreContext } = props;
const context = React.useContext(AdminStoreContext )
and from the context you an get your values, hope this is helpfull
context.//get any value you put on the state
Unfortunately after digging for a while it looks like there's no straightforward way to do this and no plans to change it (at least for now), based on this GitHub issue's response https://github.com/ReactTraining/react-router/issues/7495.
You have to define where you want to use the name prop when defining the Outlet component
const outlet = ( props ) => {
return (
<h1>{props.name}</h1>
);
};
I've been refactoring a small application that was initially within one file into it's own separate components. Currently I have a child component UsersTable that I am rendering within the parent Users2. I am passing some dummy data from the parent as props to the child but am getting the lovely Cannot read property 'map' of undefined.
I am using react hooks and passing props with the spread operator in the parent:
<UsersTable {...columns} {...data} />
And the child is receiving that here:
export const UsersTable = props => {
const [usersState, setUsersState] = useState(props)
useEffect(() => {
setUsersState(props)
}, [props])
const renderUsers = () => {
if (usersState) {
return usersState.map(d => items(d))
} else {
return noData
}
}
As well as down in the return function here:
<ActionList columns={usersState}>{renderUsers}</ActionList>
I am specifically trying to figure out why the data prop (an array of objects), is returning undefined. Linking my sandbox here. I wondering if the issue is perhaps related to passing multiple separate props via spread operators.
Any help or advice around what I am trying to accomplish would be much appreciated!
That's not a correct way to pass down props.
Props are passed as properties of an object and hence you need to define a name and value to it.
For ex, you need to write,
<UsersTable {...columns} {...data} />
as
<UsersTable columns={columns} data = {data} />
Now the UserTable component will get this props object,
props = {
columns=the column data,
data = the data
}
To use this props, you can use destructuring
const {data, columns} = props;
or you can use the dot notation,
props.column & props.data
You need to pass by attribute
<UsersTable columns={...columns} data={...data} /> /*<-- Changes */
export const UsersTable = props => {
const [usersState, setUsersState] = useState(props)
useEffect(() => {
setUsersState(props)
}, [props])
const renderUsers = () => {
if (usersState) {
return usersState.map(d => items(d))
} else {
return noData
}
}
<ActionList columns={usersState}>{renderUsers}</ActionList>
In User2 component, import UsersTable component need change from this:
<UsersTable {...columns} {...data} />
to this:
<UsersTable columns={columns} data={data} />
And in UserTable component you need to change:
const [usersState, setUsersState] = useState(props)
to:
const [columns, setColumns] = useState(props.columns)
const [users, setUsers] = useState(props.data)
renderUsers will be:
const renderUsers = () => {
if (users) {
return users.map(d => items(d))
} else {
return noData()
}
}
And last, import ActionList component like this:
<ActionList columns={columns}>{renderUsers()}</ActionList>
After that, UsersTable component will working fine.
Parent Component:
<UsersTable columns={columns} data={data} />
See my github for an example of how to use hooks and props in a similar way:
https://github.com/RyanJMorris11/helloReactHooks/blob/master/src/components/userList.js
I have a seemingly trivial question about props and function components. Basically, I have a container component which renders a Modal component upon state change which is triggered by user click on a button. The modal is a stateless function component that houses some input fields which need to connect to functions living inside the container component.
My question: How can I use the functions living inside the parent component to change state while the user is interacting with form fields inside the stateless Modal component? Am I passing down props incorrectly?
Container
export default class LookupForm extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false
};
}
render() {
let close = () => this.setState({ showModal: false });
return (
... // other JSX syntax
<CreateProfile fields={this.props} show={this.state.showModal} onHide={close} />
);
}
firstNameChange(e) {
Actions.firstNameChange(e.target.value);
}
};
Function (Modal) Component
const CreateProfile = ({ fields }) => {
console.log(fields);
return (
... // other JSX syntax
<Modal.Body>
<Panel>
<div className="entry-form">
<FormGroup>
<ControlLabel>First Name</ControlLabel>
<FormControl type="text"
onChange={fields.firstNameChange} placeholder="Jane"
/>
</FormGroup>
);
};
Example: say I want to call this.firstNameChange from within the Modal component. I guess the "destructuring" syntax of passing props to a function component has got me a bit confused. i.e:
const SomeComponent = ({ someProps }) = > { // ... };
You would need to pass down each prop individually for each function that you needed to call
<CreateProfile
onFirstNameChange={this.firstNameChange}
onHide={close}
show={this.state.showModal}
/>
and then in the CreateProfile component you can either do
const CreateProfile = ({onFirstNameChange, onHide, show }) => {...}
with destructuring it will assign the matching property names/values to the passed in variables. The names just have to match with the properties
or just do
const CreateProfile = (props) => {...}
and in each place call props.onHide or whatever prop you are trying to access.
I'm using react function component
In parent component first pass the props like below shown
import React, { useState } from 'react';
import './App.css';
import Todo from './components/Todo'
function App() {
const [todos, setTodos] = useState([
{
id: 1,
title: 'This is first list'
},
{
id: 2,
title: 'This is second list'
},
{
id: 3,
title: 'This is third list'
},
]);
return (
<div className="App">
<h1></h1>
<Todo todos={todos}/> //This is how i'm passing props in parent component
</div>
);
}
export default App;
Then use the props in child component like below shown
function Todo(props) {
return (
<div>
{props.todos.map(todo => { // using props in child component and looping
return (
<h1>{todo.title}</h1>
)
})}
</div>
);
}
An addition to the above answer.
If React complains about any of your passed props being undefined, then you will need to destructure those props with default values (common if passing functions, arrays or object literals) e.g.
const CreateProfile = ({
// defined as a default function
onFirstNameChange = f => f,
onHide,
// set default as `false` since it's the passed value
show = false
}) => {...}
just do this on source component
<MyDocument selectedQuestionData = {this.state.selectedQuestionAnswer} />
then do this on destination component
const MyDocument = (props) => (
console.log(props.selectedQuestionData)
);
A variation of finalfreq's answer
You can pass some props individually and all parent props if you really want (not recommended, but sometimes convenient)
<CreateProfile
{...this.props}
show={this.state.showModal}
/>
and then in the CreateProfile component you can just do
const CreateProfile = (props) => {
and destruct props individually
const {onFirstNameChange, onHide, show }=props;