2

I need to change the state on a value and then re render a component. This component uses the new set value as part of the URL to retrieve same data.

I'm using React and TypeScript and I created two function components, one that changes the state and a child component that receives that new state as props.

Here is the code.

const Main :React.FC = ()=>{

    const [status, setStatus] = useState('hold');

    return(
        <div >
            <Row >
                <Col >
                    <Nav >                    
                        <Nav.Item >
                            <Nav.Link href='#'  onClick={()=>setStatus('active')} >Active </Nav.Link> 
                        </Nav.Item>
                        <Nav.Item >
                            <Nav.Link  href='#' onClick={()=>setStatus('hold')} >Idle </Nav.Link>
                        </Nav.Item>
                        <Nav.Item >
                            <Nav.Link  href='#' onClick={()=>setStatus('close')}>Close </Nav.Link>                   
                        </Nav.Item>
                    </Nav>
                </Col>            
            </Row>
            <Row >            
                <Col >
                    <CardBody status={status} />  // CHILD COMPONENT     
                </Col>                                        
            </Row> 
        </div>       
    );
};
export default Main;

Any Ideas why the state does not change or why it might not re render?

EDIT

Adding the child component code:

const useFetch = (url:any) => {
    const dataInfo =  fetch(url)
    .then(  response => response.json());    
    return dataInfo;
}

export default  ( status:any ) =>{    

const [chats, setChats] = useState([]);

const estado= status.status;

     useEffect( ()=>{        
        useFetch(`http://localhost:8901/api/chat/2/${estado}`).then(data => setChats(data.message));        
     },[]);

    return (
        <div>            
            {                    
                chats.map((data:IProps, index:any)=>{
                    return (
                      <Accordion key={index}>
                        <Card >
                        <Card.Header >
                            <Accordion.Toggle as={Link} variant="link"  eventKey="0">
                            <Card.Title>  <span> {data.CLIENTNAME}</span> </Card.Title>
                            </Accordion.Toggle>
                        </Card.Header>
                        <Accordion.Collapse eventKey="0">
                            <Card.Body>
                                <Card.Title>{data.COMPANY}</Card.Title>
                                <Card.Text> {data.DESCRIPTION}</Card.Text>                                
                            </Card.Body>
                        </Accordion.Collapse>
                        </Card> 
                        </Accordion>
                    )
                })   
            }
        </div>                  
    );
} 

This code runs fine the first time the page loads. I put a {status} on the parent component and I see that the status its changing. But I don't know why it's no re rendering the child component.

FINAL SOLUTION

adding STATUS to the useEffect() on the child component, final code is:

     useEffect( ()=>{        
        useFetch(`http://localhost:8901/api/chat/2/${estado}`).then(data => setChats(data.message));        
     },
[status]); // added status here 

Thanks for the answers!

1
  • 2
    What makes you think it didn't change? Did you put logging in the body Main and you only see it rendering once? If instead main is rerendering and the issue is that CardBody isn't doing what you want, you'll probably need to share CardBody's code with us. Commented Jan 8, 2020 at 14:35

3 Answers 3

1

Try adding another useEffect to your child component and add the status prop as a dependency. That should get called every time the status changes.

useEffect(() => {
    // This should get called every time status changes
    console.log("Status ------>", status);
}, [status])
Sign up to request clarification or add additional context in comments.

1 Comment

I add the status to the useEffect() of the child component, has you pointed out, and it work perfectly. Thanks a lot.
0

I believe you should use preventDefault() before changing your state. i.e:

<Nav.Link
    href='#'
    onClick={(e)=> {
            e.preventDefault();
            setStatus('active');
        }
    }
>
    Active
</Nav.Link> 

this is usually happens when you need to override a default behavior of an underlying API.

Comments

0

EDIT:

Parent Component:

type Status =
  | "no-status"
  | "active"
  | "hold"
  | "close"

  interface IState {
    status: Status;
  }

const Main: React.FC = ()=>{
    const [status, setStatus] = useState<IState>("no-status");
    return(
        <div>                
           <a href='#'  onClick={()=>setStatus("active")} >Active </a> 
           <a href='#' onClick={()=>setStatus("hold")} >Idle </a>
           <a href='#' onClick={()=>setStatus("close")}>Close </a>           
           <Cardbody status ={status}/>        
      </div>     
    );
};

export default Main;

Child Component

const Cardbody: React.FC = (props: any)=>{
    return(
         <div>    
             {props.status}
      </div>     
    );
};
export default Cardbody;

__

I can't solve typing yet - but I think that's enough

this solution can be further optimized - by closing in the loop, and closing the "active", "hold", "close" variables in some array / object - but unfortunately I can't do it

5 Comments

This seems better suited as a comment than an answer.
Ok, i'ill remember - plans to edit the answer after receiving more information.
Thanks to your comment @PiotrŻak I put a {status} on my code and I see that the status is changing. But no re rendering
I'm getting an error => Argument of type '"no-status"' is not assignable to parameter of type 'IState | (() => IState)'. TS2345 I'm not sure how this solve the problem, because the child component render fine the first time the page load, but after changen the states it does not render again. Thanks for the code @PiotrŻak

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.