Can we access props passed to the component in a custom function - reactjs

this may sound silly but I can't find a guide to this.
what I'm trying to do is changing a variable named update in parent.
and in the parent DOM do :
<Child update={this.state.update} />
and in the child instead of picking it up between render and return (with const {update} = this.props) and only being able to use it in the DOM, I'd like to pick it up in the section between the constructor and render and use it in a function there.

You can access the props to the component anywhere in the component whether it be the constructor, lifecycle functions, render or custom functions.
The only thing that you need to know is that constructor, lifecycle methods and render function are already have binding to the context of the React component, but for custom function you need to add binding yourself. Binding can be done in the constructor or by declaring the functions as arrow functions.
Check this answer on why you need to bind custom functions: Why do we need to bind function and eventHandlers in React and what is the difference between the different binding methods
For your case
<Child update={this.state.update} />
where Child could be
class Child extends React.Component {
componentDidMount() {
const {update} = this.update || {};
console.log(update);
this.somefunc();
}
somefunc = () = {
const {update} = this.update || {}; //After function is binded, you can do the same thing here too
console.log(update);
}
}

React has a lifecycle of functions called on a component: https://reactjs.org/docs/react-component.html
On startup of component you can use componentDidMount()
if you want to change state based on props change use: componentWillReceiveProps()
Otherwise if you want the result of that function to use as data for in your view (but just manipulated). Than make a seperate function also called: computed property of computed function. (because the result is computed based on current state/props). React will make sure you don't re-render/compute unnecessary.

Related

React: Modify Parent State While Child Renders

Hooks are usually much nicer than classes, so I'm trying to pass down the ability to set a parent's state in a child of that parent using hooks. Specifically, I'm doing something like this:
class Parent extends Component {
render = () => {
return <>
<Child useRegisterFoo={foo => {...;this.setState(foo);...;}} />
{ renderBasedOnRegister() }
</>
}
}
The goal is to be able to define the child like this:
const Child = ({useRegisterFoo}) => {
useRegisterFoo(1);
useRegisterFoo(2);
}
I will define many such children, and thus having such a simple useRegisterFoo to register a particular property of the child would be really useful.
The problem is that react complains if it's done this way, understandably, as I'm modifying the state of the parent while the parent is being rendered. Specifically it says:
Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
What's a better approach at this problem? My main goal is to make the API from the perspective of the child as convenient as possible.
You are invoking the callbacks directly in the function body. This is an unintentional side-effect and shouldn't be done. Even in function components you still need to work with the component lifecycle.
Warning: Cannot update during an existing state transition (such as
within render). Render methods should be a pure function of props
and state.
The entire body of a function component is the "render" function. Use the useEffect hook to invoke these passed callbacks, or conditionally call them as part of an event handler.
Example:
Use an useEffect hook with an empty dependency array to trigger the effect only once when the component mounts.
const Child = ({useRegisterFoo}) => {
useEffect(() => {
useRegisterFoo(1);
useRegisterFoo(2);
}, []); // <-- empty dependency, effect triggered once on mount
...
}

const value between class components in React

I have a class component which renders a const. all the values needed for its evaluation are inside that component. However for purposes of splitting up and keeping the code clean, it is used in another class component. How do i connect them?
Code:
Class component1 extends React.Component
///code
render() {
const {allFacts, currentPage, factsPerPage } = this.state
const indexOfLastFact = currentPage * factsPerPage
const indexOfFirstFact = indexOfLastFact - this.state.factsPerPage
const allFactsSliced = allFacts.slice(indexOfFirstFact, indexOfLastFact) <-- THIS
}
///
export default component1
the last const, allFactsSliced, is then used in another component:
Class component2 extends React.Component
///code
render() {
const renderAllFacts =
this.state.isLoading ? <div id="loading">///</div> :
allFactsSliced.map((fact, index) => <--- HERE
{return <div>Fact # {index +1}: <br/> {fact.fact}</div>})
is this possible, good practice, or am i just needlesly complicating things and should keep everything in one component?
You can pass information into React components either by props, context, or a pure JS function or object.
So, if you want to pass allFactsSliced (or any other data) from one component to another, you have to do that by either props or context (since that particular piece of data is derived from the state of a component, you can't do it by a pure JS function or object).
If you have a parent/child relationship between these components, then you can pass derived state from the parent to the child (here it would have to be component1 to component2). If they are siblings, then you have to lift the state (see the React docs: https://reactjs.org/docs/lifting-state-up.html).
If it's more a grandparent or great-grandparent, then you can consider putting that derived state from component1 into a context and having component2 consume that context.
It's worth mentioning that you'll re-render any components that rely on that prop or context when it changes it, so it may be faster to keep it in one component. Or it might not be. Profile it and check if it matters.
But, if you want to pass a value from one component to another, it's always either as a prop or a context.

How to explicitly create an optional property in a React component when it is not specificied?

In a React component I need a ref to the HTML element I use for some manual processing (e.g. to listen to resize events). I can do that by defining a ref member in my component and set that in the render method:
render() {
return <div ref={this.myRef} />;
}
However, sometimes the owner of this component also needs this ref for other work (e.g. dynamic handling of certain other events). It makes sense to use the same ref here, so I added a property to the component:
render() {
const { innerRef } = this.props;
return <div ref={innerRef} />;
}
The problem is now that the parent component not always uses the inner ref, so it doesn't specify it when creating the inner component. In order to maintain the functionality of the inner component I want to explicitly create the ref if not given by the parent like:
public constructor(props: MyProps) {
super(props);
if (!props.innerRef) {
props.innerRef = React.createRef<HTMLElement>();
}
}
However, that's not accepted because props is read only. What other approach could I take to accomplish this explicit init, if not provided?
Note: I tried to use the static defaultProps to provide such a default, but defaultProps is used for all instances of the class, so they all share the same default ref then. Hence this is not a good approach.
Instead of trying to directly assign a new value to props, check if the innerRef is available from the props and if not pass an internally created ref to the div like this.
<div ref={innerRef || internallyCreatedRef} />

React Hooks - How to avoid redeclaring functions on every render

On a react class I would write something like this
class Myclass extends React.Component {
handleUpdate = info => {
//do the update
}
render() {
return (
<SomeMarkup>
<SomeComponent onUpdate={this.handleUpdate} />
</SomeMarkup>
)
}
}
If using a function I could just write the following
function MyFunction() {
function handleUpdate(info) {
// do the update
}
return (
<SomeMarkup>
<SomeComponent onUpdate={handleUpdate} />
</SomeMarkup>
)
}
...but with that I'd be redeclaring a function on every render. Is there any sort of trick that would memoize the handler function between renders? Or should I just move the handler out of the render scope? (Moving it out of the render scope requires me that I explicitly pass more parameters since I wont directly have access to the function scope.)
This is exactly the scenario that useCallback is for. The function still gets declared every time with useCallback, but the function returned is memoized so that if it is passed as a property to children, the children will receive a consistent function unless it has to change due to dependencies changing.
Please see my recent related answer here that demonstrates in detail how useCallback works:
Trouble with simple example of React Hooks useCallback
Here's another related answer: React Hooks useCallback causes child to re-render

Assigning props to variable in React class component

I have a simple react component. I would like to assign a variable inside the component method to props. I've tried this method works with functional components:
class Pets extends React.component {
constructor(props) {
super(props)
}
const {dog, cat, frog} = props
// the code on the line above does not work
render() {
return (
<div>
{dog.name}
{cat.name}
</div>
)
}
}
That will not work. props is a property on the instance of the component you created with <Pets /> JSX for example. It needs to be inside the instance methods of the class Pets. It will work if you do it in the render method by const {dog, cat, frog} = this.props. props in the class body as you have now in the question is not what them expected to be.
Inside the constructor function just const {dog, cat, frog} = props will work, because here props object is received as an argument. so this.props (after the super(props) line)andprops` is same object.
Generally you unpack props where you need them, for example you need those inside the render to create some output, so you unpacked it there. I tried to explain in this answer what props means in the class body, and instance methods body, how you can access the props in different methods etc. But as xadm said, unpacking them inside the constructor by thinking you will access them later in other methods will not work due to the scope boundary, unless you store them as a property to the instance again using this.dog = props.dog. But this is an horrible idea, never do this. Just unpack them when you need any property from props object in that place only.

Resources