Как перерисовать компонент react при изменении url?

Рейтинг: 0Ответов: 1Опубликовано: 30.01.2023

В MainOdds использую хук useLocation, который отслеживает текущий url и подставляет параметр в url запроса к api. При клике в компоненте Menu меняется url, но перерисовки компоненты MainOdds не происходит. Подскажите, как сделать так чтобы перерисовался MainOdds при изменении url?

import React from 'react'
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Unstable_Grid2';
import { useState, useEffect } from 'react';
import { competitionOddsApi, upcomingOddsApi } from '../../Api/SportsApi';
import { Divider, Stack} from '@mui/material';
import { useLocation, useNavigate } from 'react-router-dom';
import axios from 'axios';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: theme.palette.text.secondary,
}));


const MainOdds = () => {


  const instance = axios.create({
    params: {
      regions: 'eu',
      oddsFormat: 'decimal',
      markets: 'h2h,spreads,totals',
      dateFormat: 'iso'
    },
    headers: {
      
    }
   })
  
  
  
  
  const competitionOddsApi = () => {
    
     
    return instance.get(`https://odds.p.rapidapi.com/v4/sports/${sportKeyLocationMain}/odds`)
    .then(response => {
      console.log(response.data)
      
      return response.data;
      
    })
  }

    const [error, setError] = useState(null);
    const [isLoaded, setIsLoaded] = useState(false);
    const [items, setItems] = useState([]);

    const location = useLocation();
    const sportKeyLocation = location.pathname;
    const sportKeyLocationMain = sportKeyLocation.split('/')[2];
    console.log(sportKeyLocationMain);
  
    
    useEffect(() => {
    //  upcomingOddsApi()
    competitionOddsApi()
       
        .then(
          (result) => {
            setIsLoaded(true);
            setItems(result);
            console.log(result);
           
          },
          
          (error) => {
            setIsLoaded(true);
            setError(error);
          }
        )
    }, [])
    
    if (error) {
      return <div>Error: {error.message}</div>;
    } else if (!isLoaded) {
      return <div>Loading...</div>;
    } else {
  
    }
  
console.log(items);


  return ( <div> <Item>Top matches</Item>
     {items.map(key => {
    return <div key={key.id} variant="inherit">
    <Box sx={{ width: '100%' }}>
    <Stack spacing={2}>
  <Item>{key.sport_title}</Item>
  <Item>{key.home_team}{'  ' }vs{ '  '}{key.away_team}</Item>
  <Stack
  direction="row"
  divider={<Divider orientation="vertical" flexItem />}
  spacing={5}
  justifyContent="space-around"
>
  {key.bookmakers[0].markets[0].outcomes.map(key => {
    return <Item key={key.id}>{key.name} {'   '}  {key.price}</Item>
  })}
  </Stack>
  </Stack>
 
 
  
  
  </Box>
    </div>

  })}
    </div>
  )
}

export default MainOdds

Ответы

▲ 0Принят

Не происходит перерисовка, потому что компонент не понимает, что состояние изменилось.

Я бы предложил, изменить логику работы функции competitionOddsApi и добавить в нее сохранение полученных значений от АПИ

  const competitionOddsApi = () => {
      instance.get(`https://odds.p.rapidapi.com/v4/sports/${sportKeyLocation}/odds`)
        .then(
          (result) => {
            setIsLoaded(true);
            setItems(result.data);
            console.log(result.data)
          },
          (error) => {
            setIsLoaded(true);
            setError(error);
          }
        )
  }

Убрать useEffect(() => {}, [])

Создать переменную состояния для хранения текущегу url

const location = useLocation();
//const sportKeyLocation = location.pathname;
const [sportKeyLocation, setSportKeyLocation] = useState(location.pathname);

И создать 2 useEffect

  useEffect(() => { // Вызывает апи при изменении sportKeyLocation
    //  upcomingOddsApi()
    competitionOddsApi();
  }, [sportKeyLocation]);

  useEffect(() => { // Сохраняет новый URL в переменную
    setSportKeyLocation(location.pathname)
  }, [location.pathname]);

В таком случает, при изменении location.pathname ее значение будет сохранено в состоянии компонента и при изменении данного состояния будет вызвана функция competitionOddsApi()

Так же можно попробовать переписать функцию competitionOddsApi что бы она на вход принимала значение location.pathname и подставляла его в АПИ. В таком случае, можно будет уйти от лишней переменной состояния и второго вызова useEffect