I'm calling a component <B setHasChecked={()=>{setCheckedClientId(true)}}/> from within component "A", inside component "A" I declare the hook const [checkedClientId, setCheckedClientId] = useState(false);, and inside component "B" I execute props.setHasChecked();.
Even though this is working fine, i still get an error on the console:
React has detected a change in the order of Hooks called by "A"
Previous render Next render
------------------------------------------------------
1. useState useState
2. undefined useRef`
that's because you are not passing any parameter to props.setHasChecked();
I would suggest better pass a callback function from A to B. And in the callback function which resides in A you can call the setChecked function.
I have a few questions related to each other regarding React hooks: useState and useCallback.
When exactly is a functional update required?
1.1. If the setter function receives a function its argument will ALWAYS be the previous state?
If I want to update the parent state from the child component, how should I pass the setter to the child- wrap it in another function as a callback as explained here? just pass it directly as suggested here?
2.1. What are the reasons and advantages/disadvantages of each approach?
If I can just pass it directly and I am using memo, is useCallback required as explained here?
If I want to use the most recent state data when updating the parent state from the child, how should I do this?
4.1. Is passing a callback to the child useful in that case?
1. When exactly is a functional update required?
You may need to update any state on your component. For example, you are getting user from server via api and you need to store that user on your component. To do so, you need useState to store that user object. Here is the example:
const [user, setUser] = useState({}); // declaration
let newUser = u; // u is coming from api
setUser(newUser);
1.1. If the setter function receives a function its argument will ALWAYS be the previous state?
Yes. setter function like setState is used in class component. Here is the example of only update a state field:
this.setState({username: 'khabir'});
here you are updating state using previous state:
this.setState(prevState =>{
return{
counter : prevState.counter +1
}
})
2. If I want to update the parent state from the child component, how should I pass the setter to the child- wrap it in another function as a callback as explained here? just pass it directly as suggested here?
Both examples are same. you can use anyone.
3. If I can just pass it directly and I am using memo, is useCallback required as explained here?
If you pass any function reference to the child component from parent component, it is being created on every render of Parent and hence prevProps and props is not the same anymore even though they are.
To apply the memo, we need to make sure that function reference is not unnecessarily recreated on every render of Parent. That's why useCallback is used. Please read that article completely for better understanding.
4. If I want to use the most recent state data when updating the parent state from the child, how should I do this?
You can not update parent state directly from child component but you can send function reference to child component and call that function from child component that defined (the function) on parent component. In that function body (in parent), you can update your state of parent component.
4.1. Is passing a callback to the child useful in that case?
Yes as I said on the answer of question number 4.
If i have a function that i want to send to a component as a prop
// Bind the function
this.myFunc = this.myFunc.bind(this)
// Create the function
myFunc(X) {
this.props.anotherFunc(X).result === 'Something' && .....
}
// Pass the function as prop
<OtherComponent myFunc={this.myFunc} />
However the function is already using a prop from another class, and i get "cannot read property 'result' of undefined"
So how can i pass a function as a prop if that function is already using another prop from another component ?
You should try render props Render Props, its is a technique for sharing code between react component using props whose value is a function. Another method is Higher order component.
I am new to VueJs and I am doubtful about passing the optional payload
Could anyone please tell me how to pass the value returned by a computed function in the child component to the parent component using the optional payload.
I want to implement a separate independent search component which returns the search results to all other components. The computed function looks like this:
get computedSports () {
if (!this.searchModel || this.searchModel.length === 0)
return this.sports
else
return this.fuseSearch.search(this.searchModel)
}
This is how I am trying to pass the value returned by computed function to its parent component in the child template:
#input="$bus.$emit('computed-sports', computedSports)"
In the parent component, this is how I am trying to access the value of the child's computed function:
v-on:computed-sports=""
I am not quite sure how to access the value here. Could anyone help me out in this?
Thanks!
The argument to a v-on should be a method or inline function that takes the payload as an argument. For example
v-on:computed-sports="handleComputedSports"
and your method might be defined
handleComputedSports(theValue) {
console.log("The value is", theValue);
}
There's an example in this section of the documentation. Your emit is fine. The fact that the value comes from a computed makes no difference to anything.
Im trying to build an small React.js application and my component structure looks like this:
MainComponent
- CategoryList
-Category
- ItemsList
-Item
My MainContent component does an ajax request for its state data in the componentDidRender: which returns this object:
data:[
Object[0]
-name
-items[]
,
Object[1],
Object[2]
]
Now, I want my CategoryList to write out all the Categories by name, which works just fine, but I also want to print out the items of the selected category. This is my ItemsList component:
var ItemsList = React.createClass({
render:function(){
var itemNodes = this.props.category.items.map(function(item){
return (
<Item name={item.name} />
);
});
return(
<div className="itemList">
{itemNodes}
</div>
);
}
});
And this is how I pass on the "category"-property from my the parent component
<ItemsList category={this.state.data[0]} />
I get an error say "Can´t read property items of undefined" meaning that the category prop never was assigned. I know that this.state.data contains an array of objects so I don´t see the error here.
What do I do wrong?
EDIT: Per request, this is my MainComponent:
var MainComponent = React.createClass({
getInitialState:function(){
return {data: []};
},
componentDidMount:function(){
$.ajax({
type:'get',
url: '/categories',
dataType: 'json',
success:function(data){
this.setState({data: data});
}.bind(this)
});
},
render: function(){
return (
<div className="row">
<div className="col-md-6">
<CategoryList categories={this.state.data} />
</div>
<div className="col-md-6">
<ItemsList category={this.state.data[0]} />
</div>
</div>
);
}
});
Your main component initializes the state with an empty array in data. A render would always fail because there is no this.state.data[0].
One would probably reply that the ajax request will provide the value for this state property data (supposing that your web service is providing a valid array). However, this only happens after the response was received from the server, which will not happen after the first render.
If the information was available immediately, one could either setState on the method componentWillMount or the component constructor, so as to avoid triggering a second render:
componentWillMount() is invoked immediately before mounting occurs. It
is called before render(), therefore setting state synchronously in
this method will not trigger a re-rendering. Avoid introducing any
side-effects or subscriptions in this method.
In this case, since we are waiting for remote information, the React documentation still recommends the use of componentDidMount, as well employed here:
componentDidMount() is invoked immediately after a component is
mounted. Initialization that requires DOM nodes should go here. If you
need to load data from a remote endpoint, this is a good place to
instantiate the network request. Setting state in this method will
trigger a re-rendering.
Therefore, the component's render method must be able to handle the missing state variable. There are multiple ways to approach this, but preventing the nested element from being rendered until we have data is the easiest approach. With some additional logic, the application could inform the user that the particular component is loading.
render() {
return (
<div className="row">
<div className="col-md-6">
<CategoryList categories={this.state.data} />
</div>
<div className="col-md-6">
{this.state.data.length > 0 &&
<ItemsList category={this.state.data[0]} />
}
</div>
</div>
);
}
I can corroborate the previous answer.
Modern (2023) React tells you to use functional components. So, if you want to upload data from a server to render it inside a component you need to use so-called 'hooks' named 'useEffect' and 'useState'.
So first you import them:
import React, { useEffect } from "react";
import { useState } from "react";
Next, you create a functional component and initialize 'state' and 'set_state function' inside a component:
export default function FuctionName() {
let [ value, set_value ] = useState([])
}
This would create the 'value' variable which would preserve its state across renders.
Then, you make a fetch request (before the component's return statement) (but you need to put it inside of the useEffect function for a consistent behavior):
useEffect(() => {
fetch('url')
.then(response => response.json())
.then(server_data => {
set_value(server_data);
})}
, [])
Now, you see why we need state: because we need to store data returned from the server inside a variable and we need this data to preserve across renders.
Also, you think that now you can use your data inside the component's return render like this:
return (
<h1>the data from server: {value.name_of_key}</h1>
)
But you encounter the error of 'reading undefined'.
First, check if the server returns the correct type of object. Put a console.log statement inside the fetch request:
useEffect(() => {
fetch('url')
.then(response => response.json())
.then(server_data => {
set_value(server_data);
console.log(server_data);
})}
, [])
It should be a list with objects inside, like: [{}, {}, {}].
If it is, then the problem is that component renders before it receives the data from the server. The component will first render, then receive the data from the server. If you call the state variable inside the render statement it will call the empty state.
So, in order to mitigate it, your code should be ready to render both the empty state and the state with data. The easy way to do so would be conditional rendering. Render the component with data only if there is data to render:
return (
{value && <h1>the data from server: {value.name_of_key}</h1>}
)
the 'value &&' part lets you implement the logic:
if the value (data from the server) is empty don't render anything (thus do not call any keys from data)
if the value is not empty, render the component which calls to data
Why is that so? The '&&' expression (a and b) evaluates from right to left. If first variable evaluates to 'false', then it does not go further and stops there. The initial state of variable 'value' is an empty object ('let [ value, set_value ] = useState([])' - remember?). So, when the server has not returned data yet on the first render, the expression 'value &&' evaluates to 'false' and does not render the right part of the expression. When the server has returned the data, it calls the 'setState' function with data and forces to render the component the second time. The second time expression 'value &&' evaluates to 'true' and React goes to the right part of the expression and actually renders the component with data. You can check this process by placing console.log statement inside the fetch request and inside the return statement and you will see the order of functions resolutions.
Hope it helps.
Also, check out the article:
https://daveceddia.com/react-before-render/
Happy coding >>