How Destructuring Works In Function Parameters - javascript

I tried to search on this but no luck so far. I've looked at destructuring info on the web. I don't understand though this partcular pattern of destructuring.
const App = ({todos, actions}) => (
<div>
<Header addTodo={actions.addTodo} />
<MainSection todos={todos} actions={actions} />
</div>
)
what is {todos, actions} doing here in the function's param definition? What todos and actions is it pulling from?

If you call App like App({todos:10,actions:{addTodo: addTodoFunction}}) in the App function the arguments todos and actions get assigned to 10 and {addTodo: addTodoFunction} respectively. So actions.addTodo becomes addTodoFunction. More at Object Destructuring.

Those are the props that React passes to your component:
<App todos={...} actions={...} />
So you could write your component without destructuring like this:
const App = (props) => (<div>
<Header addTodo={props.actions.addTodo} />
<MainSection todos={props.todos} actions={props.actions} />
</div>)
React passed the props to your component as an object, and destructuring extracts properties from an object, so it is a shortcut!
You could also destructure your props in two steps:
const App = (props) => {
const { todos, actions } = props
return (<div>
<Header addTodo={actions.addTodo} />
<MainSection todos={todos} actions={actions} />
</div>)
}
Notice that in this last case you have to use curly braces and return explicitly because there are multiple statements in your arrow function.

Related

Two components with the same state/functions but different UI

I have two components that take the exact same props and share the exact same methods. But they have different UIs. How would you recommend keeping this DRY? My first idea:
Create a Wrapper component that has the onClick method and props/state.
Create two UI components that take in the props/state and then render as they need to, such as:
<Wrapper>
<UIComponent-1 />
</Wrapper>
<Wrapper>
<UIComponent-2 />
</Wrapper>
Is there some better way to do this? I was thinking of making the wrapper an HOC but then the onClick functionality would need to be duplicated (or imported from some common file).
You could split your component into multiple components. Have one component act as the API/interface, defining the props that can be used and have a render prop that will take in the presentational component that you want to render in a certain case
Here is an example implementation of andy mccullough's answer.
This example creates a component that holds a string that can be reversed by calling the reverse function. Both the value and the reverse function are then provided to the render property. You can then decide how you attach the function to the DOM (if at all) and where and how the value is displayed.
I've also added a default render property, but if you don't have a default scenario this can be omitted.
The functions provided to render are currently anonymous functions, but if you want to re-use them you can store them in a variable or export them.
const {Fragment, useState} = React;
const {Alert, Button} = ReactBootstrap;
const defaultRender = ({value, reverse}) => <span onClick={reverse}>{value}</span>;
function Reversible({initialValue = "", render: Render = defaultRender}) {
const [value, setValue] = useState(initialValue);
const reverse = () => setValue(value => value.split("").reverse().join(""));
return <Render value={value} reverse={reverse} />;
};
ReactDOM.render(
<Fragment>
<Reversible initialValue="default render" />
<Reversible
initialValue="custom Alert render"
render={({value, reverse}) => (
<Alert variant="primary" onMouseEnter={reverse} onMouseOut={reverse}>
{value}
</Alert>
)}
/>
<Reversible
initialValue="custom Button render"
render={({value, reverse}) => (
<Button onClick={reverse}>{value}</Button>
)}
/>
</Fragment>,
document.getElementById("root")
);
<link rel="stylesheet" crossorigin="anonymous" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" />
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-bootstrap#next/dist/react-bootstrap.min.js"></script>
<div id="root"></div>
You could have a custom hook of the common methods then call the hook inside the function components. Looks like your issue has been specified https://reactjs.org/docs/hooks-effect.html.
As an example
const useCustomHook = (someArgs) => {
// perform some effects
return value;
}
// Then your component
const Component = (props) => {
const value = useCustomHook(someArgs);
return <div></div>
}
I hope it helps.

How to pass React Component as props to another component

I am trying to call PopupDialog.tsx inside Content.tsx as a sibling of Item.tsx.
Previously PopupDialog.tsx is called inside C.tsx file but due to z index issue i am trying to bring it out and call it in Content.tsx
Is it possible to somehow pass the whole component(popupDialog and its parameters) in Content.tsx so that i could avoid passing back and forth the parameters needed for popupdialog in content.tsx.
Code in C.tsx where PopupDialog component is called.
const C = (props: Props) => (
<>
{props.additionalInfo ? (
<div className="infoButton">
<PopupDialog // need to take this code out and want to add in Content.tsx
icon="info"
callback={props.callback}
position={Position.Right}
>
<div className="popuplist">{props.additionalInfo}</div>
</PopupDialog>
</div>
) : (
<Button className="iconbutton"/>
)}
</>
);
Content.tsx where i would like to call PopupDialog.tsx with its parameters
const Content = (props: Props) => {
const [componentToRender, docomponentToRender] = React.useState(null);
const [isAnimDone, doAnim] = React.useState(false);
return (
<div className="ContentItems">
<PWheel agent={props.agent} />
{isAnimDone && (
<>
<Item {props.agent} />
{componentToRender &&
<PopupDialog/> //want to call here with all its parameters to be passed
}
</>
)}
</div>
);
};
Folder Structure
App.tsx
->ViewPort.tsx
->Content.tsx
->PWheel.tsx
->Item.tsx
->A.tsx
->B.tsx
->C.tsx
{props.additionalinfo &&
->PopupDialog.tsx
->PopupDialog.tsx
So if I understand the question correctly you want to pass one component into another so that you can use the properties or data of the passed componenet in your current component.
So there are three ways to achieve this.
1)Sending the data or entire component as prop.This brings disadvantage that even though components which don't require knowledge
about the passed component will also have to ask as a prop.So this is bascially prop drilling.
2)The other is you can use context api.So context api is a way to maintain global state variale.so if you follow this approach you don't need to pass data or componenet as props.Wherever you need the data you can inport context object and use it in componenet.
3)Using Redux library.This is similar to context api but only disadavantage is that we will have to write lot of code to implement this.Redux is a javascript library.
Let me know if you need more info.
You need to :
<>
<Item {props.agent} />
{componentToRender &&
<PopupDialog abc={componentToRender} /> //you must call in this component, in this case i name it is abc , i pass componentToRender state to it
}
</>
and then PopupDialog will receive componentToRender as abc, in PopupDialog , you just need to call props.abc and done .
If you need to know more about prop and component you can see it here
I think what you want to use is Higher-Order-Components (HOC).
The basic usage is:
const EnhancedComponent = higherOrderComponent(WrappedComponent);
Below is such an implementation that takes a component (with all its props) as a parameter:
import React, { Component } from "react";
const Content = WrappedComponent => {
return class Content extends Component {
render() {
return (
<>
{/* Your Content component comes here */}
<WrappedComponent {...this.props} />
</>
);
}
};
};
export default Content;
Here is the link for higher-order-components on React docs: https://reactjs.org/docs/higher-order-components.html
Make use of
useContext()
Follow this for details:
React Use Context Hook

How to access ref that was set in render

Hi I have some sort of the following code:
class First extends Component {
constructor(props){super(props)}
myfunction = () => { this.card //do stuff}
render() {
return(
<Component ref={ref => (this.card = ref)} />
)}
}
Why is it not possible for me to access the card in myfunction. Its telling me that it is undefined. I tried it with setting a this.card = React.createRef(); in the constructor but that didn't work either.
You are almost there, it is very likely that your child Component is not using a forwardRef, hence the error (from the React docs). ref (in a similar manner to key) is not directly accesible by default:
const MyComponent = React.forwardRef((props, ref) => (
<button ref={ref}>
{props.children}
</button>
));
// ☝️ now you can do <MyComponent ref={this.card} />
ref is, in the end, a DOMNode and should be treated as such, it can only reference an HTML node that will be rendered. You will see it as innerRef in some older libraries, which also works without the need for forwardRef in case it confuses you:
const MyComponent = ({ innerRef, children }) => (
<button ref={innerRef}>
{children}
</button>
));
// ☝️ now you can do <MyComponent innerRef={this.card} />
Lastly, if it's a component created by you, you will need to make sure you are passing the ref through forwardRef (or the innerRef) equivalent. If you are using a third-party component, you can test if it uses either ref or innerRef. If it doesn't, wrapping it around a div, although not ideal, may suffice (but it will not always work):
render() {
return (
<div ref={this.card}>
<MyComponent />
</div>
);
}
Now, a bit of explanation on refs and the lifecycle methods, which may help you understand the context better.
Render does not guarantee that refs have been set:
This is kind of a chicken-and-egg problem: you want the component to do something with the ref that points to a node, but React hasn't created the node itself. So what can we do?
There are two options:
1) If you need to pass the ref to render something else, check first if it's valid:
render() {
return (
<>
<MyComponent ref={this.card} />
{ this.card.current && <OtherComponent target={this.card.current} />
</>
);
}
2) If you are looking to do some sort of side-effect, componentDidMount will guarantee that the ref is set:
componentDidMount() {
if (this.card.current) {
console.log(this.card.current.classList);
}
}
Hope this makes it more clear!
Try this <Component ref={this.card} />

Is const Component = () => (<div></div>) the same as const Component = () => {return(<div></div>)} in React?

I'm guessing they are the same since the output is the same, but is it the official shorthand in Redux or is it a Javascript property? I am following through the Redux documentation and have one component as such:
const App = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
)
and another component as such:
const AddTodo = ({ dispatch }) => {
let input
return (
<div>
<form
onSubmit={e => {
e.preventDefault()
if (!input.value.trim()) {
return
}
dispatch(addTodo(input.value))
input.value = ''
}}
>
<input ref={node => (input = node)} />
<button type="submit">Add Todo</button>
</form>
</div>
)
}
I'm wondering if this is something to do with Javascript or React.
I understand that in Javascript, the arrow function needs to have a () like
(name, description) => ({name: name, description: description});
to describe that it is an object and not a plain function in case of inline, single-expression syntax, but I'm not sure if that applies here in the Redux example since the JSX portion is not an object. Please help me with my mistake.
Short answer, yes, as JSX and React follows the very same syntax the JavaScript uses, since JSX is merely a syntax extension to React. You may read more about JSX over here.
In addition, regarding your point about the redux, your redux should be written purely in JavaScript (or TypeScript), without any JSX syntax, since the main objective of your redux store is to maintain your application's state, rather than to render logic.
It's mostly for readability, you can omit the parentheses and it will function the same
const App = () =>
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
But when you have a body inside the component and want to return the JSX on a new line you have to wrap in in parentheses to avoid ASCI(automatic semicolon insertion)
const App = () => {
const x = 'something'
return (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
)
}

React/ES6: curly braces in function signature? [duplicate]

I know you can pass all a react components props to it's child component like this:
const ParentComponent = () => (
<div>
<h1>Parent Component</h1>
<ChildComponent {...this.props} />
</div>
)
But how do you then retrieve those props if the child component is stateless? I know if it is a class component you can just access them as this.prop.whatever, but what do you pass as the argument into the stateless component?
const ChildComponent = ({ *what goes here?* }) => (
<div>
<h1>Child Component</h1>
</div>
)
When you write
const ChildComponent = ({ someProp }) => (
<div>
<h1>Child Component {someProp}</h1>
</div>
)
From all the props that you are passing to the childComponent you are just destructuring to get only someProp. If the number of props that you want to use in ChildComponents are countable(few) amongst the total number of props that are available, destructuring is a good option as it provides better readability.
Suppose you want to access all the props in the child component then you need not use {} around the argument and then you can use it like props.someProp
const ChildComponent = (props) => (
<div>
<h1>Child Component {props.someProp}</h1>
</div>
)
Are you looking for the ES6 named argument syntax (which is merely destructuring) ?
const ChildComponent = ({ propName }) => (
<div>
<h1>Child Component</h1>
</div>
)
const ChildComponent = (props) => ( // without named arguments
<div>
<h1>Child Component</h1>
</div>
)
Optionally there is a second argument to your function depending of whether you specified a context for your component or not.
Perhaps it would be more helpful wityh a links to the docs. As stated in the first article about functional components. Whatever props passed on to the component is represented as an object passed as first argument to your functional component.
To go a little further, about the spread notation within jsx.
When you write in a component :
<Child prop1={value1} prop2={value2} />
What your component will receive is an plain object which looks like this :
{ prop1: value1, prop2: value2 }
(Note that it's not a Map, but an object with only strings as keys).
So when you're using the spread syntax with a JS object it is effectively a shortcut to this
const object = { key1: value1, key2: value2 }
<Component {...object}/>
Is equivalent to
<Component key1={value1} key2={value2} />
And actually compiles to
return React.createElement(Component, object); // second arg is props
And you can of course have the second syntax, but be careful of the order. The more specific syntax (prop=value) must come last : the more specific instruction comes last.
If you do :
<Component key={value} {...props} />
It compiles to
React.createElement(Component, _extends({ key: value }, props));
If you do (what you probably should)
<Component {...props} key={value} />
It compiles to
React.createElement(Component, _extends(props, { key: value }));
Where extends is *Object.assign (or a polyfill if not present).
To go further I would really recommend taking some time to observe the output of Babel with their online editor. This is very interesting to understand how jsx works, and more generally how you can implement es6 syntax with ES5 tools.
const ParentComponent = (props) => (
<div>
<h1>Parent Component</h1>
<ChildComponent {...props} />
</div>
);
const ChildComponent = ({prop1, ...rest}) =>{
<div>
<h1>Child Component with prop1={prop1}</h1>
<GrandChildComponent {...rest} />
</div>
}
const GrandChildComponent = ({prop2, prop3})=> {
<div>
<h1>Grand Child Component with prop2={prop1} and prop3={prop3}</h1>
</div>
}
You can use Spread Attributes reducing code bloat. This comes in the form of {'somearg':123, ...props} or {...this.props}, with the former allowing you to set some fields, while the latter is a complete copy. Here's an example with ParentClass.js :
import React from 'react';
import SomeComponent from '../components/SomeComponent.js';
export default class ParentClass extends React.Component {
render() {
<SomeComponent
{...this.props}
/>
}
}
If I do, <ParentClass getCallBackFunc={() => this.getCallBackFunc()} />, or if I do <ParentClass date={todaysdatevar} />, the props getCallBackFunc or date will be available to the SomeComponent class. This saves me an incredible amount of typing and/or copying/pasting.
Source: ReactJS.org: JSX In Depth, Specifying the React Element Type, Spread Attributes. Official POD:
If you already have props as an object, and you want to pass it in JSX, you can use ... as a “spread” operator to pass the whole props object. These two components are equivalent:
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}```
Now, let's apply this to your code sample!
const ParentComponent = (props) => (
<div>
<h1>Parent Component</h1>
<ChildComponent {...props} />
</div>
);
I thought I would add a simple ES2015, destructuring syntax I use to pass all props from a functional parent to a functional child component.
const ParentComponent = (props) => (
<div>
<ChildComponent {...props}/>
</div>
);
Or if I have multiple objects (props of parent, plus anything else), I want passed to the child as props:
const ParentComponent = ({...props, ...objectToBeAddedToChildAsProps}) => (
<div>
<ChildComponent {...props}/>
</div>
);
This destructuring syntax is similar to the above answers, but it is how I pass props along from functional components, and I think it is really clean. I hope it helps!
But how do you then retrieve those props if the child component is stateless?
const ChildComponent = ({ *what goes here?* }) => (
<div>
<h1>Child Component</h1>
</div>
)
ChildComponent holds the name and the props will be the argument in the arrow function syntax just as you need:
const ChildComponent = props => (
<div>
<p>{props.value ? props.value : "No value."}</p>
</div>
);
If you Babel-it it will create something like this:
var ChildComponent = function ChildComponent(props) {
return React.createElement(
"div",
null,
React.createElement(
"p",
null,
props.value ? props.value : "No value."
)
);
};
For some reason, what seems to work for me is a variation on Shubham's answer above:
const ChildComponent = props => (
<div>
<h1>Child Component {props[0].someProp}</h1>
</div>
)
Using this
const ParentComponent = ({ prop1, prop2, prop3 }) => (
<div>
<h1>Parent Component</h1>
<ChildComponent {...{ prop1, prop2, prop3 }} />
</div>
);
const ChildComponent = ({ prop1, prop2, prop3 }) =>{
<div>
<h1>Child Component with prop1={prop1}</h1>
<h1>Child Component with prop2={prop2}</h1>
<h1>Child Component with prop2={prop3}</h1>
</div>
}

Categories

Resources