Ogundipe Pelumi
Ogundipe Pelumi

Reputation: 57

Filter an array every time a function is executed and my react state change

I'm working on a project that has to do with playlist, so what I want to execute is whenever one of the songs on the playlist is clicked the image that is attached to the song should be viewed. So, I have my code this way...

const Component = () => {
  const value = useContext(DataContext);

  const [data, setData] = useState(null);
  const [currentData, setCurrentData] = useState(null);

  useEffect(() => {
    const url =
      "https://52-90-82-235.maverickmaven.com/geotourdata/json.cfm?h=-107,37,s,en,3A771765";

    const currentValue = value;

    axios({
      method: "get",
      url,
      responseType: "stream",
    }).then((response) => {
      let features = response.data.features.filter((elem) => {
        return elem.type === "Feature";
      });

      setData(features);

      const currentDatafile = data?.filter((data) => {
        return data?.assets[0].audio === value;
      });
      setCurrentData(currentDatafile);
    });
  }, [setCurrentData]);
};

So, what this code does is that it returns the array that has the picture, but the problem is that it only filters once and repeatedly returns the same value even if I click on another song, and I need it to filter every time I clicked on the songs(i.e the function is executed).

I tried filtering and mapping at the same time, but it didn't work. or maybe I didn't write the syntax well enough.

Please I need help.

Upvotes: 0

Views: 1185

Answers (2)

Umer Bhat
Umer Bhat

Reputation: 30

Move these lines to new useEffect hook. Will trigger after you set data

useEffect(() => {
  const currentDatafile = data?.filter((item) => {
    return item.assets[0].audio === value;
  });
  setCurrentData(currentDatafile)},[data])

Upvotes: 1

AKX
AKX

Reputation: 169051

You shouldn't re-fetch the data from the remote source every time. I've wrapped that in a custom hook instead, here (and a custom fetcher function to make testing/mocking easier).

Then, you shouldn't hold the selected object in the state unless you need to modify it internally (in which case you should copy it into a state atom anyway); instead, just hold the ID.

function fetchTourData() {
  return fetch('https://52-90-82-235.maverickmaven.com/geotourdata/json.cfm?h=-107,37,s,en,3A771765')
    .then(response => response.json())
    .then(data => data.features.filter((elem) => elem.type === 'Feature'));
}

function useTourData() {
  const [data, setData] = React.useState(null);
  React.useEffect(() => {
    fetchTourData().then(setData);
  }, [setData]);
  return data;
}

const Component = () => {
  const tourData = useTourData();
  const [selectedId, setSelectedId] = React.useState(null);
  const selectedTour = (tourData || []).find(t => t.id === selectedId);
  if (tourData === null) {
    return <div>Loading</div>
  }
  return (
    <div>
      <div>
        Selected: {JSON.stringify(selectedTour || "nothing")}
      </div>
      <ul>
        {tourData.map(t => <li key={t.id}><a href="#" onClick={() => setSelectedId(t.id)}>{t.name}</a></li>)}
      </ul>
    </div>
  );
};

ReactDOM.render(<Component />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions