so I have this custom hook which returns an array of Objects from database, before it gets data, the value of returned value is undefined. getDataByID(100).doc?.items - This returns the items from database as an array. How can I make sure that the returned Value is not undefined and then mount the component in functional components?
Try to fetch this data in parent component, and when you received the data then only mount required component as child component and pass those data as props.
{
(dataFromAPI !== undefined) ? <ChildComponent data={dataFromAPI} /> : undefined
}
In this way when you have dataFromAPI then only your child component will be mounted.
Mujibur Rehman Ansari's answer can furthur modified as
{ dataFromAPI && <ChildComponent data={dataFromAPI} /> }
Related
I'm passing some data from parent to children like the following
<Children title={title}/>
Inside the children I have a state like this :
const [state,setState] = useState(title ? title : '')
Problem is, when accessing the title directly like this {title} it's working, accessing state on the other hand does not work. Should I useEffect for this to get data from parent when the state is loaded ?
You need to use useEffect hook here. because useState is basically used to initialize the value and not to update.
useEffect(() => {
setState(title);
}, [title]);
Because the problem with your approach is that when you do -
const [state,setState] = useState(title ? title : '')
This will set your state variable to ''(empty string) because on the initial render of your child component there is no guarantee that you are going to get the value of title.
And when you get the value of title in your props. useState will not detect it.
So therefore to detect a change in your props and to setState based on updated props its recommended to use useEffect.
Access the props in the children component like this -
function childComponent(props) {
//props.title -- access it in your component.
}
But what you're trying in your code is not recommended, you can't mutate the state of props. Read React docs
This is the correct implementation of this;
<ClassA title = "class a"/>
function ClassA(props){
// access the title by calling props.title
}
i'm getting stuck , there is expenseForm (children) .if you look onSubmit takes an object "expense" why we need at this place .indeed we already dispatch some action .
<Expenseform onSubmit={expense => {
props.dispatch( AddExpenses (expense));
props.history.push("/");
}}
/>
props are designed in react to pass data from parents to children.
** change in props triggers a rerender of the component that the props are passed to, which refreshes your UI
if you are not passing data from parent to child, you don't need them. It depends on what you want to do with your component.
I have set up a searchbar as the child component and pass it two props, one is the array of cards that I am rendering and the other is function, which should setState as the search field changes.
<Searchbar quesCards={questionCards} filter={this.filter} /> :
Now this questionCards is a state variable containing the array of cards to be displayed.
questionCards.push(
<QuestionCard
id={i}
question={question.question}
answer={question.answer}
isMarked={question.isMarked}
isPublished={question.isPublished}
validity={question.validity}
category={question.category}
/>
)
this.setState({ questionCards, newCards: questionCards, loading: false });
Here <QuestionCard /> is another component, but I believe it has nothing to do with the issue.
Inside my child component, I call this.props.filter with the filtered results like this:
handleChange = name => event => {
//filtering the data ...
this.props.filter(newCards);
}
This I do inside onChange function of <Searchbar/>
Back in the Parent Component,
filter = (newCards) => {
console.log(newCards); //displays the desired result
this.setState({ newCards }); //the state changes, but is not rendered on screen
}
After this setState, the component should re-render with the new results. But it doesn't happen so.
Please note that it is newCards which is getting displayed, since the beginning and questionCards is used only to pass as prop
I have already tried this.forceUpdate
Also, if I console log inside the function filter, newCards contains correct results, but it is not getting re-rendered after this.setState({ newCards })
I think the problem is that your data flow is inefficient.
Your filter input within searchBar, should update some filter state (locally). It looks like just need to filter the questions from your filter state.
The consumer of <SearchBar /> does not need to know the filter.
const list = questions.filter(item => (
// item.name[enter_property] === this.state.filter
))
Then just .map() over list.
—
What condition are you matching? A specific property or multiple of them?
You are generating QuestionCard like this
questionCards.push(
<QuestionCard
id={i}
question={question.question}
answer={question.answer}
isMarked={question.isMarked}
isPublished={question.isPublished}
validity={question.validity}
category={question.category}
/>
)
But ,your updating the newCards state variable ,can u check that?
If its not resolved , can u post your full code.
I have a parent component that fetches data in componentDidMount() hook. The state is setState()-d with this data. Then I pass the data to the child components as props and set their state based on these props. On the first render the props will be undefined because componentDidMount() hasn't executed yet. So, the child components get undefined props and the state is created with them. When the data fetches in componentDidMount() new props are passed to the child components, but the state is already created with undefined props and nothing changes. So, I am aware of two solutions now:
Use componentWillRecieveProps(). But this is now deprecated.
Use stateless child components. Pass the data to them as props from
the parent component and don't set a state(use the data from props),
and when the parent does a setState() in componentDidMount(), this
will cause a re-render to child components with new props and
everything works.
Now, what if I want to have stateful child components? I can't use the second method, and the first one is deprecated. What is the best solution to accomplish this?
static getDerivedStateFromProps(props, state)
is invoked right before calling the render method, both on the initial mount and on subsequent updates. It should return an object to update the state, or null to update nothing.
This method exists for rare use cases where the state depends on changes in props over time.
static getDerivedStateFromProps(nextProps, prevState){
if(nextProps.someValue!==prevState.someValue){
return { someState: nextProps.someValue};
}
else return null;
}
For more details enter link description here
You can read this blog post.
In short a better approach would be to use fully uncontrolled component with key.
Add a key to the child component based on data. If the data changes, the key changes and child component will re-mount.
Provide data as props to the child, use this props as default state of child component.
Here is a sandbox example
Consider using the replacement for componentDidReceiveProps, getDerivedStateFromProps, if you have state within a component which is informed by the values of the props it receives.
https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
I am trying to pass props to child component but the child is always receiving an empty.
Here's the code to make it clearer.
When I pass to child component a state, it works
Here's the working code:
render() {
return (
<div>
<PostList list={ this.state.posts }></PostList>
</div>
);
}
But in my case, I want pass the props from the redux state
Not working code:
render() {
return (
<div>
<PostList list={ this.props.posts }></PostList>
</div>
);
}
}
function mapStateToProps(state) {
return {
posts: state.posts.all,
postDetail: state.posts.post
}
}
Any ideas why the PostList is getting an empty object in the second case even though this.props.posts is not actually empty in the calling component?
Thanks
Install redux-devtools to see what your redux state actually looks like. For example, if you have used combineReducers(), then .posts may be prefixed with the name of a reducer.
Once you have verified the actual redux state, then double-check mapStateToProps to ensure you're referencing the correct state slice. In your question, I wonder if you may need to adjust it, but I cannot be sure without first knowing what your redux state is.
function mapStateToProps(state) {
return {
posts: state.posts
}
}
Please confirm what you are exporting. I assume your render() method is contained within a class? If so, ensure you export the result of connect(). Something like this:
export default connect(mapStateToProps, mapDispatchToProps)(MyReactClass)
Shouldn't you just attach to store in your child component? You can pass information where to attach if it's dynamic. Though passing store value by props sounds like a bad idea.
as for your example - this.props.posts props are intial values, re-render is not caused by props change inside your scope. Clearer explaination:
If parent changes props of child component - that cause re-rerender.
If parent changes it's own props then no re-rerender triggered. (this.props shouldn't be mutated)
If you want to cause an action use state - pass props to state. Then any manipulation on state will cause re-render of child.
<PostList list={ this.state.posts }></PostList>
Attaching to redux-state is triggered after your props are created therefore it's empty when child is called and (as said above) it won't trigger re-render.
edited:
Well, my answer was a bit chaotic. Let me try again.
Solution:
attach to store or wherever you get your data and pass this data to
this.state.posts = data. In constructor of your component set default state, like this.state = { posts: [] } (or whatever structure is required). In render() change your call for child into <PostList list={ this.state.posts }></PostList> and there you have it.
Notice:
Anyways since you're using redux I believe it would be better if you'd just attach to redux store inside your child component.