Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Dúvida] Dificuldade de pegar o state atualizado com useContext

Boa tarde, Alguns detalhes sobre meu problema rs -Eu estou usando o React dentro do NEXTJS13, só estou explicando isso pois é por essa razão que eu tenho que usar async function dentro do useEffect porque meu componente é "use client"

Meu grande problema é que quando eu tento puxar o state objetos la no meu componente nav a primeira vez que roda ele funciona e aparece mas quando eu atualizo a pagina ele da undefined. Eu sei que o setState ele nao atualiza automaticamente, mas alguem saberia me informar se tem algum "jeito" de pegar o valor atualizado?

(Eu apaguei partes do codigo que nao tem conexao com o problema para nao ultrapassar o limite de caracteres.)

Eu estou tentando treinar o trabalho com states no react mas estou enfrentando essa dificuldade de como conseguir acessar o state atualizado, no meu componente nav que esta abaixo se eu tento acessar {objetos[1].name} na primeira renderizacao ele aparece normal mas quando a funcao verificacao é chamada ou se eu atualizo a pagina ele da esse erro TypeError: Cannot read properties of undefined (reading 'name') como se o meu state estivesse indefinido mas se eu acesso com uma condicao {objetos.length ? objetos[1].name : "Nada aqui"} ele aparece normalmente e nao da mais erro

Meu componente Nav

    export default function NavBar(){
    const {login, setLogin} = useContext(loginContext);
    const {objetos} = useContext(SensorsContext)
    
    return(
        <Navbar>
            <Container fluid className={styles.navMain}>
                <Nav>
                    <Nav.Link>
                        {/* Se eu uso assim nao funciona 
                            {objetos[1].name}
                            Da o erro
                            TypeError: Cannot read properties of undefined (reading 'name')
                        */}
                        
                        {/* Com a condicao aparece normal*/}
                        {objetos.length ? objetos[1].name : "Nada aqui"}
                        
                        
                    </Nav.Link>
                </Nav>
            </Container>
        </Navbar>
    )
}

Meu componente que tem o useEffect no qual estou criando os objetos e alimentando o estado.

export default function InfoTable(){

    const {objetos, setObjetos} = useContext(PokeContext);
    useEffect(()=>{
        let temp = []
       
        async function fetchData(){
            const promises = pokeList.map(async(item)=>{
                return await getPokemon(item,1000)
            })
        
            const results = await Promise.all(promises)

            for(const result of results){
                const local = getLocation(locais) // gera valores aleatorios
                
                const newObjeto = {
                    name: result.name,
                    status: true,
                    birthDate: await getBirth(result.name,1000),
                    lat:local[0], 
                    lon:local[1],
                    num:createNumber()
                }
                temp.push(newObjeto)
            }
            setObjetos(temp)
        }

        async function verificacao() {
   
          const promises = pokeList.map(async (item) => {
            return await getPokemon(item, 1000);
          });
          const results = await Promise.all(promises);
        
          const newObjetos2 = await Promise.all(
            results.map(async (result, index) => {
              const local = getLocation(locais). // gera valores aleatorios
              return {
              // coloquei a palavra novo para testar qual ia ser renderizado pois so estou monitorando o num
                name: `Novo ${result.name}`, 
                status: true,
                birthDate: await getBirth(result.name, 1000),
                lat:local[0], 
                lon:local[1],
                num: `Novo ${createNumber()}`,
              }}));
          setObjetos((objetosAntigos) => {
            const novosObjetos = objetosAntigos.map((objetoAntigo, index) => {
              const newObjeto = newObjetos2[index];
              if (newObjeto.num !== objetoAntigo.num) {
                return{
                  ...objetoAntigo,
                 num: newObjeto.num
                }
                
              } else {
                return objetoAntigo;
              }
            });
            return novosObjetos;
          });
        }
        fetchData()
        const intervalId = setInterval(() => {
          verificacao(objetos);
        }, 2000);
        return () => clearInterval(intervalId);
    },[])
2 respostas
solução!

Oi Otto, tudo bem?

É importante lembrar que o setState não atualiza automaticamente o state, então é necessário encontrar uma forma de obter o valor atualizado.

Uma solução para esse problema é utilizar o useEffect no componente Nav e passar o state objetos como dependência. Dessa forma, toda vez que o state for atualizado, o useEffect será executado novamente e você terá acesso ao valor atualizado.

Aqui está um exemplo de como você pode implementar isso:

export default function NavBar(){
    const {objetos} = useContext(SensorsContext)
    
    useEffect(() => {
        // Aqui você pode realizar qualquer lógica necessária com o state atualizado
        console.log(objetos);
    }, [objetos]);

    return(
        <Navbar>
            <Container fluid className={styles.navMain}>
                <Nav>
                    <Nav.Link>
                        {objetos.length ? objetos[1].name : "Nada aqui"}
                    </Nav.Link>
                </Nav>
            </Container>
        </Navbar>
    )
}

Dessa forma, toda vez que o state objetos for atualizado, o useEffect será executado e você poderá realizar as operações necessárias com o valor atualizado.

Um abraço e bons estudos.

Realmente o unico jeito de eu acessar o valor atualizado é usando a condicao.

TypeError: Cannot read properties of undefined (reading 'name') Source src/Components/Nav/NavBar.jsx (30:36) @ name

28 | {login ? "User " : "Login "} 29 | {name}

30 | {objetos[0].name} | ^

//Ele só funciona se eu coloco a condicao {objetos.length ?objetos[0].name : "nada"}

export default function NavBar(){ const {login, setLogin,name,setName} = useContext(loginContext); const {objetos} = useContext(SensorsContext)

useEffect(()=>{
    console.log(objetos)
},[objetos])
return(
    <Navbar>
        <Container fluid className={styles.navMain}>
            <Navbar.Brand>
                {login ? "Ta aqui" : "nao ta"}
            </Navbar.Brand>
            <Nav>
                <Nav.Link onClick={() => {
                    setLogin(!login);
                }}>
                    {login ? (<BsBroadcast color="green" />) : (<BsBroadcast color="red" />)}
                    {login ? "User " : "Login "}
                    {name}
                    {objetos.length ?objetos[0].name : "nada"}
                </Nav.Link> 
                <Nav.Link onClick ={()=>{setName("Joao")}}>
                    ChangeUser
                </Nav.Link>
            </Nav>
        </Container>
    </Navbar>
)

}