cant pass react state to a child after setState()? - javascript

I'm working on reactjs project
where I fetching data from firestore and set the app.js state to the fetched data, and I pass this state to a child of app.js to display it but it's undefined at first then it consoles the right state.
How can I make the child component render only after its props is correct?!
fetchDataFromFirestore = async () => {
let dataRefFromFirestore = database.doc('items/fruitsDataJsonFile');
(await dataRefFromFirestore).onSnapshot((snapshot) => {
let fetchedItems = snapshot.data();
this.setState({
fetchedItems: fetchedItems.data
},
console.log('DONEEE ADIING'))
})
}

You can use a concept called "Conditional Rendering".
It will be like
{!!this.state.fetchedItems?.length &&
<YourChildComponent fetchedItems={this.state.fetchedItems}>
Then, your child component will be rendered only when the state has array data.
Similarly, your child component will have props called fetchedItems with full data.
Reference: https://reactjs.org/docs/conditional-rendering.html

Related

React Component rendering twice, props 'undefined' at first render

I have a react child component (FinalReport.js) that is rendering twice, except that on the first render, one of the props is undefined for some reason, which is throwing an error. Of course I could add error handling but that doesn't seem like best practice.
The Parent Component contains user inputs which are saved as a useState Hook (esrData) upon pressing a 'Save' button. The first child component (Airload.js) contains more inputs and calls an API, and saves the result as a useStateHook (airLoadRes). Both hooks are defined in the parent component and passed as props. The child component in question (FinalReport.js) ONLY renders once both hooks become available, and then passes the hooks along. Why is FinalReport rendering twice and why is airLoadRes undefined on the first render? Strict Mode is not being used. Any help is appreciated!
Parent Component
const GenerateEnergySavings = () => {
const [esrData, setEsrData] = useState();
const [airLoadRes, setAirLoadRes] = useState();
...
return( ...
// Child Component 2
{(esrData && airLoadRes != undefined) ?
<PDFViewer height='1000px' width='1000px'>
<FinalReport esrData={esrData} airLoadRes={airLoadRes} />
</PDFViewer> : ''}
...
// Child Component 1 (API)
<Airload airLoadRes={airLoadRes} setAirLoadRes={setAirLoadRes} />
Child Component 1
EDIT: I should mention this is a bootstrap modal
const Airload = ({ airLoadRes, setAirLoadRes }) => {
...
// Airload API
const getAirLoadCalc = async () => {
console.log(airloadData)
await Axios.post('https://localhost:44418/airload', airloadData)
.then(res => {
setAirLoadRes(res.data)
console.log(res)
setKey(6)
}).catch(err => {
alert(err)
})
}
}
Child Component 2
// This is rendering twice!! ONLY airLoadRes comes in as undefined on first render
export const FinalReport = ({ esrData, airLoadRes }) => {
console.log(esrData)
console.log(airLoadRes)
...
This code (const [airLoadRes, setAirLoadRes] = useState();) initialize airLoadRes as undefined.
That's why it is undefined on first render.
React does render on each change of the state, context, or properties. So, I guess FinalReport is rendered twice because of changes on esrData state. Or other state which you possibly have in the code.

React - Accessing data from child component without rendering child component

I am trying to access data within a deeply nested child component by passing a callback function from the parent component through various child components.
For example, say that this is the parent component that I am rendering:
function ParentComponent = () => {
const [data, setData] = useState();
const callback = (obj) => {
setData(obj);
}
return <p>{data}</p>
}
And I am trying to retrieve data from the nested component in a different file:
// I need to call this component somehow from the parent component
function InitialChildComponent = ({cb}) => {
return <NestedChildComponent cb={cb}/>
}
// this component cannot directly be called from ParentComponent
function NestedChildComponent = ({cb}) => {
let data = 'abc';
cb(data);
return <p> don't want this displayed </p>
}
Is there any way to run the callback function from within the nested child component without displaying the JSX in that same nested component? Or is there another better method of accessing this data from the nested child component?

React when pass data to child throw props data duplicate

I'm create Activities function component and call child function component called Categories when i send categories list to Categories function component and log "props" data send twice first one is empty and second has data as follow
Activies
function Activities() {
const [category, setCategory] = useState([]);
function handelChange({ target }) {
setCategory({
...category,
[target.name]: target.value,
});
}
useEffect(() => {
getCategories().then((_categories) => setCategory(_categories));
}, []);
return (<Categories category={category} onChange={handelChange} />)
}
and categories component
function Categories(props) {
console.log(props);
return (<div></div>)
}
i'm trying to log props in useEffect but problem still exist
This is happening because of how the life cycle in React works. This is correct and expected behavior. Before you load the categories, it is a blank array on the initial render. Then it gets the categories, updates the state, and re-renders, this time with categories.
renders with the initial state(empty)
goes and fetches categories
re-renders with the categories
This is entirely expected. That double log is the initial render and then the updated state render. Remember React is a heavily async library. The useEffect doesn't happen during render, it happens after render. Every state update will also cause an update and thus another log. It might be helpful to research what will cause a React render and how the life cycle behaves.
I think you handleChange function should update item in a array of object not change the state object completely
function handelChange({ target: {name, value} }) {
setCategory(categories => {
const categoryIndex = categories.findIndex(pr => pr.id === id);
const category = categories[categoryIndex];
return [
...categories.slice(0, categoryIndex)),
{
...category,
[name]: value,
},
...categories.slice(categoryIndex + 1))
]);
}

React.JS - Child Componenet Not Updating When Recieving Props (Function Components)

I have a higher order functional component in my app that passes JSON to it's child component. I am using react Hooks to manage state. I can't use componentDidUpdate since this is not a class component.
I'm using useEffect() to get it to process the JSON on initial render, but after that I can't seem to get it to update. I've confirmed the PROPS are indeed changing and the JSON is unique (it changes on the click of a button).
Here is my code:
function FormSection(props) {
const [questions, updateQuestions] = useState([]);
const [sectionJSON, updateSectionJSON] = useState(props.json);
const fetchQuestionsData = json => {
/* API CALL TRANSFORM JSON INTO HTML FOR USE ELSEWHERE IN THE APP */
};
useEffect(() => {
fetchQuestionsData(sectionJSON);
}, [sectionJSON]);
...
}
I've also tried changing the useEffect() hook to use props directly:
useEffect(() => {
fetchQuestionsData(props.json);
}, [props.json]);
The parent componenet is calling it as follows:
<FormSection key={i} json={newJSON} />
Is there something obvious I am missing?
When you set,
const [sectionJSON, updateSectionJSON] = useState(props.json);
is equivalent to,
constructor(props){
super(props);
this.state = {
sectionJSON: props.json
}
}
So your sectionJSON will set only once and any subsequent change in props.json will not change sectionJSON.
So this will execute only once, and not when props.json changes
useEffect(() => {
fetchQuestionsData(sectionJSON);
}, [sectionJSON]);
To make this work you need to pass props.json to your useEffect hook as,
useEffect(() => {
fetchQuestionsData(props.json);
}, [props.json]);
Doing this will not re-render your component, because your component's state is not changing, like we do using componentDidUpdate in class based component, so you should set your state in fetchQuestionsData like,
const fetchQuestionsData = json => {
/* API CALL TRANSFORM JSON INTO HTML FOR USE ELSEWHERE IN THE APP */
updateSectionJSON(json); //This will re-render your component.
};

ReactJs connect 2 child components

If in Angular 2 is possible to connect two child components with each other how is it manageable in react js?
A) You can use Redux or Flux to keep a single state for the whole application, which you will be able to access from any component that you decide to connect with this state, called the Store.
You can read more about this in https://github.com/reduxjs/redux.
B) If both components are siblings, and the state you are trying to share is not something that you would care about in the rest of the application, you can pass the state from the parent to both children, as props, and also pass a function that allows the children to set the parent's state.
For example:
class Parent extends Component {
state = {
something: '',
}
changeSomething = (e) => {
this.setState({
something: e.target.value,
})
}
render() {
const { something, changeSomething } = this.state;
return(
<div>
<ChildrenA
something={something}
changeSomething={changeSomething}
>
<ChildrenB
something={something}
changeSomething={changeSomething}
>
</div>
);
}
Now both children have access to this.props.something and this.props.changeSomething and they can both change the parent's state and both will see the changes.
Hope it helps

Categories