I'm trying to send an object as 'props' from a parent Class into a Child class with the intention of showing information:
Parent class
const TaskDetail = () => {
//Get parameter from URL
const { id } = useParams()
const [taskDetail, setTaskDetail] = useState([])
useEffect(() => {
TaskService.getTaskById(id)
.then(response => {
setTaskDetail(response.data);
})
}, [id]) //This [id] avoid infinite loop of requests
if (!taskDetail) return <div>No data</div>
return (
<div>
<Detail taskDetail={taskDetail}/>
</div>
)
}
This class makes a request to the server and gather a data object. This object is then passed onto the Child Detail where it will be deserialized and visualized accordingly.
Child class
const Detail = ({ taskDetail }) => {
return (
<Box
align='center'
justifyContent='center'
sx={{ width: '100%', marginTop: 4}}
bgcolor=''
//border='solid'
>
<Stack
//border='solid'
sx = {{width: '50%'}}
justifyContent='center'
//border='solid'
>
<Typography
sx = {{ marginTop: 5}}
variant='h4'
fontWeight='bold'
bgcolor='#b2dafa'
>NOMBRE DEL EJERCICIO<br/>{taskDetail.taskName}</Typography>
<Box
sx = {{ marginTop: 3}}
bgcolor='#b2dafa'
>
<Typography
variant='h5'
align='center'
sx = {{ margin: 2}}
fontWeight='bold'
>DETALLES DEL EJERCICIO</Typography>
<Typography
sx = {{ margin: 2}}
variant='text'
border='#555'
>{taskDetail.details}
</Typography>
</Box>
<Box
sx = {{ marginTop: 5}}>
<Typography
variant='h6'
>Marca para completar</Typography><Toogle
label=''
toogled={false}
onClick={null}/>
<br></br>
</Box>
{taskDetail.id}
<Box
sx = {{ marginTop: 2}}>
<AddComment taskId={taskDetail.id}/>
</Box>
<Box
sx = {{ marginTop: 2}}>
<ListComments taskId={taskDetail.id}/>
</Box>
</Stack>
</Box>
)
}
As you can observe, this object is also passed to other child components. The context is that TaskDetail shows information and then offers two features, ListComments and AddComments. At the current moment, I am having an issue in AddComment where the prop taskId={taskDetail.id}
is undefined.
Function in Child where I am having this issue
function ListComments(props) {
const [comments, setComments] = useState([])
useEffect(() => {
console.log('DEBUG listcomments: ' props.taskId)
TaskService.getTaskCommentsById(props.taskId)
.then(response => {
setComments(response.data)
})
}, [])
return (
<div>
<h2>Comentarios</h2>
{comments.map((comment, _) => {
return <Comment key={comment.id} comment={comment}/>
})}
</div>
)
}
I have noticed, that if I change something in the code and save it (re-renders the page). All of a sudden I get the atribute that I need instead of the undefined value.
How could I avoid this situation? I trust that I have made a huge mistake that I am unable to see, but its part of the learning. For this reason, I am open to suggestions.
CodePudding user response:
Since the data you get back from the service is an object I would suggest to initialize the state with an object {}
.
const [taskDetail, setTaskDetail] = useState({});
In the ListComments
component you can do the same as you did in the TaskDetail
component. Run useEffect
when the props.taskId
changes. And add a early return if the taskId
have no value yet.
useEffect(() => {
console.log("DEBUG listcomments: " props.taskId);
if (!props.taskId) return;
TaskService.getTaskCommentsById(props.taskId).then((response) => {
setComments(response.data);
});
}, [props.taskId]);
CodePudding user response:
Very cool that you're reaching out for help!
First, just a minor correction: They're not classes, they're functions / components.
I think the problem is the check condition at the top:
if (!taskDetail) return <div>No data</div>
Since taskDetail is initialised as an array, the condition will always be true since arrays are objects in javascript.
Because of this too, when you're passing it down, at least on the first render, none of these props in the lower components exist. So maybe try initalising it either as null
, or changing the condition to the following:
if (!taskDetail || taskDetail.length === 0) return <div>No data</div>
One more thing, to make sure that the data is fetched, you need to add props.taskId
to the dependency list in the List component.