React v0.14 supports pure functional components (i.e. same input equals same output). Props are passed in as function arguments.
// Using ES6 arrow functions and an implicit return:
const PureComponent = ({url}) => (
<div>
<a href={url}>{url}</a>
</div>
);
// Used like this:
<PureComponent url="http://www.google.ca" />
// Renders this:
http://www.google.ca
But how do you render children of the PureComponent? In regular stateful components you access the children with this.props.children, but this obviously doesn't work here.
const PureComponent = ({url}) => (
<div>
<a href={url}>{children}</a> // <--- This doesn't work
</div>
);
<PureComponent url="http://www/google.ca">Google Canada</PureComponent>
// I want to render this:
Google Canada
What should I do?
You need to add children to the destructuring assignment of the argument "props".
const PureComponent = ({url, children}) => (...)
children is just a prop passed to the component. In order to use it like you are using props.url you need to add it to that list so it can be "pulled out" of the props object.
Related
In react, specifically referencing the hooks/functional paradigm, when do you need to use props.functionName? As far as I can tell, if the functions are named the same, you can omit props as follows:
Parent.js
...
<Child functionName={functionName}/>
...
Child.js
...
functionName();
...
However, if the name changes, props must be referenced as follows:
Parent.js
...
<Child otherName={functionName}/>
...
Child.js
...
props.otherName();
...
Am I correct? If so, why use the second design pattern? (Perhaps just to call out that the function comes from a parent and isn't defined at the child level. Or maybe some other reason?)
No. The name you use depends entirely on how the child component processes the props it is passed. How the parent component determines what value to pass is completely irrelevant.
If the props are placed in a variable named props then you need to access them through the object stored in the variable.
const Child = (props) => {
props.functionName();
...
}
If the first argument is destructured, then each property is stored in its own variable.
const Child = ({functionName}) => {
functionName();
...
}
If the value is copied to another variable inside the component then you can also use the variable it was copied to.
const Child = (props) => {
const functionName = props.functionName();
functionName();
...
}
False, It is Destructuring Props in React;
Destructuring is a convenient way of extracting multiple values from data stored in (possibly nested) objects and Arrays
props is an object so we can use the Destructuring
Destructuring gives access to the use of props in a more readable format and discards the need for props for every property.
<Child functionName={functionName} name={name}/>;
const child = (props)=>{
// you need to write props.functionName
props.functionName();
const thisName = props.name
};
const child =({functionName,name})=>{
// you dont need to write *props.*
functionName();
const thisName = name
};
When interfacing with a child component, the name that you use for something in your parent component may be different from the prop that the child component requires.
Just for example, say that your parent component has something to do with school, and you have:
const [studentId, setStudentId] = useState();
const [parentId, setParentId] = useState();
But you also have a child component for students that expects an id prop. Then, to pass down the studentId to it, you'd do:
<Student id={studentId} />
And in that child component, you'd reference it by doing props.id.
You wouldn't want to do
const [id, setId] = useState();
in the parent component, and then
<Student id={id} />
when passing it down because then it wouldn't be clear in the parent component which ID that stateful value referred to - you'd probably have to add a comment.
If so, why use the second design pattern?
Sometimes, like in the situation I just described, the child component isn't designed with all identifiers used in the parent component in mind - which is perfectly reasonable, that's what allows for so many things in programming to be modular (and adaptable and useful). As a result, sometimes you need a prop or variable to have one name in the parent component, and another in the child component, which requires the
<Child otherName={functionName}/>
approach.
Let's say I have a component with a scrollable subcomponent, and I want to expose the ability to scroll:
const MyComponent = (props) => {
return <ScrollView ... />
}
I want to be able to do
<MyComponent ref={myRef} />
...
myRef.scrollTo({x: 0});
So I need a way to forward the ref to the <ScrollView>. Let's try putting the ref on the props:
const MyComponent = (props) => {
return <ScrollView ref={props.scrollRef} ... />
}
...
<MyComponent scrollRef={myRef} />
...
myRef.scrollTo({x: 0});
I just tried that with React Native on iOS, and it indeed works. I see several advantages over React.forwardRef:
Simpler, because I don't need to use another React API.
Works also if there is more than one child who needs ref forwarding.
Seems to me that this approach is
What's the advantage of React.forwardRef? Why was it added in React 16.3?
Note that there is no difference between using another named prop like innerRef FOR FORWARDING, it works the same.
Refactoring class components
Since React moved toward function components (hooks) you might want to refactor the class component code to a function component without breaking the API.
// Refactor class component API to function component using forwardRef
<Component ref={myRef} />
React.forwardRef will be your only option (further explained in details).
Clean API
As a library author you may want a predictable API for ref forwarding.
For example, if you implemented a Component and someone wants to attach a ref to it, he has two options depending on your API:
<Component innerRef={myRef} />
The developer needs to be aware there is a custom prop for forwarding
To which element the innerRef attached? We can't know, should be mentioned in the API or we console.log(myRef.current)
<Component ref={myRef} />
Default behavior similar to ref prop used on HTML elements, commonly attached to the inner wrapper component.
Notice that React.forwardRef can be used for function component and HOC (for class component see alternative below).
Ref forwarding is not limited to DOM components. You can forward refs to class component instances, too.
For function components, forwardRef sometimes comes with useImperativeHandle combo (in class component you just call the class methods on ref instance: ref.current.myAttr().
// Same usage
<Component ref={myRef} />
const Component = React.forwardRef((props, ref) => {
// you can forward ref <div ref={ref} />
// you can add custom attributes to ref instance with `useImperativeHandle`
// like having ref.myAttribute() in addition to ones attached to other component.
});
Important behavior of ref prop without forwardRef.
For the class component, this code alone will attach the ref to CLASS INSTANCE which is not useful by itself and need another ref for forwarding:
// usage, passing a ref instance myRef to class Component
<Component ref={myRef} />
Full example, check the logs:
// We want to forward ref to inner div
class ClassComponent extends React.Component {
innerRef = React.createRef();
render() {
// Notice that you can't just `this.props.ref.current = node`
// You don't have `ref` prop, it always `undefined`.
return <div ref={this.innerRef}>Hello</div>;
}
}
const Component = () => {
const ref = React.useRef();
useEffect(() => {
// The ref attached to class instance
console.log(ref.current);
// Access inner div through another ref
console.log(ref.current.innerRef);
}, []);
return <ClassComponent ref={ref} />;
};
In function components, it won't even work because functions don't have instances.
By default, you may not use the ref attribute on function components because they don’t have instances. [1]
forwardRef.
Refs and the DOM.
Why we need ref forwarding?
I've got a problem in my project which is pretty large therefore I can't post every part of the code here, but I'll try to summarize the main parts.
I've got a parent component which state is managed through a useReducer and which render returns a mapping of this state.
Each child has to take both the value and the index of the mapping. I'm also using the Context API to pass the dispatcher
on some of the childs.
function ParentComponent(props) {
const [state, dispatch] = useReducer(initialData, reducer);
return (
<div>
<MyContext.Provider value={dispatch}>
{state.myArray.map((value, index) => (
<ChildComponent value={value} index={index} />
))}
</MyContext.Provider>
</div>
);
}
/* Other file */
function ChildComponent({value, index}) {
const dispatch = useContext(MyContext);
return <div>
{/* Uses value and index to display some data */}
</div>
}
export default React.memo(ChildComponent, (prevProps, nextProps) => !_.isEqual(prevProps, nextProps));
Some of the childs in the tree components have to use React.memo to avoid useless re-renders, ChildComponent is one of them.
I'm using the lodash functions _.isEqual to compare the props to know when the component has to re-render.
The problem is the following. One of my components in the component tree adds items to the myArray attribute of the ParentComponent state.
When I add an item, anyway, each ChildComponent rendered from the ParentComponent mapping receives the same index of 0, creating a lot of problems.
The ParentComponent has the right indices (when I log them inside the mapping they are the right ones) but it's like the ChildComponent isn't getting it.
Is there any way to solve this? Maybe it has something to do with React.memo?
React.memo() takes a callback that should determine whether prevProps and nextProps are equal, but you're returning the negation of that.
Also using the index as a key should be considered a last resort, since this will fail to behave correctly when elements in the array are re-ordered relative to each other. You should always source the key from the data whenever possible.
I'm trying to change the state of parent component using a button in my child component by passing a function "setName" to the child. I read a lot of examples but they seemed to all use classes, where I'm trying to use functions since the React doc on hooks seems to promote functions over class.
In my parent, I have
let [Name, setName] = useState("John Doe");
And I pass the setName method by using JSX in my return statement:
<Child childSetName=({setName})/>
In my child component I have
export const Child = ({childSetName}) => {
return(
<a onDoubleClick={()=>{childSetName("Mary Ann")}}>
Click me
</a>
)}
I got a typeError: childSetNameis not a function.
I also read this popular question, but it uses class, not functions as all the hooks example from React docs are.
How can I set my parent state using child component, both retain their function structures not classes.
I think you have wrong syntax here
<Child childSetName=({setName})/>
Should change like this
<Child childSetName={setName}/>
and
export const Child = ({childSetName}) => {
return(
<a onClick={()=>{childSetName("Mary Ann")}}>
Click me
</a>
)}
I wonder if it is fine to predefine some JSX and use it multiple times in different components.
const saveButton =
<div class="u-mth u-textRight">
<Button variant="flatBlue">Save</Button>
</div>;
const test = <div>{saveButton}</div>;
Is there any downside compared to a normal functional react component?
export const SaveButton = () => (
<div class="u-mth u-textRight">
<Button variant="flatBlue">Save</Button>
</div>
);
const test = <div> <SaveButton /> </div>
And what about this one instead of functional with react props:
const saveButton = (text: string) => (
<div class="u-mth u-textRight">
<Button variant="flatBlue">{text}</Button>
</div>
);
const test = <div> {saveButton(text)} </div>;
First one is simply just jsx, it's not a component.
Second one is a stateless component, which is fine as well but you have not used any props.
Third one is also just a function not a component as you have not used props. What I would do is as #estus recommended in answer.
But please also view this link which says they way you have approached is actually faster.
React component (snippet 2) will appear as in React devtools as <SaveButton>...</SaveButton>, while other options won't.
React component (snippet 2) is the way it's usually done. If a component needs to expose dynamic behaviour, parameters should be passed as props:
const SaveButton = ({ text }) => (
<div class="u-mth u-textRight">
<Button variant="flatBlue">{text}</Button>
</div>
);
and
<SaveButton text={text} />
Helper function (snippet 3) is the way how the performance of React component can be improved, by calling it directly. It can be considered preliminary optimization, unless proven otherwise.
As long as element hierarchy doesn't expose dynamic behaviour, the definition of React elements as a variable (snippet 1) has no downside under normal circumstances. If there's a possibility that dynamic behaviour can be necessary in future (custom or localized text), it will require refactoring.
It is just declaring variables. Nothing else. In this case, using ES6 and JSX.
It is the same thing as 1. just as function. This function returns what you declared under 1. Using ES6. No downsides.
The same as 2. with arguments object, actually passing parameter to function using ES6 and Type Script.
function saveButton(props) {
return <div class="u-mth u-textRight">
<Button variant="flatBlue">{props.text}</Button>
</div>;
}
const element = <saveButton text="Save" />;
ReactDOM.render(
element,
document.getElementById('root')
);
This is the way using props and pure function.