1

Hy, let me explain my problem, i have a state of tag called tag_data :

const  [tagData, setTagData] = useState([
    { key: '1', label: 'Music', active: 0 },
    { key: '2', label: 'Sport', active: 0 },
    { key: '3', label: 'Dance', active: 0 },
    { key: '4', label: 'Cook', active: 0},
    { key: '5', label: 'Video Games', active: 0},
    { key: '6', label: 'Travel', active: 0 },
    { key: '7', label: 'Picture', active: 0 },
    { key: '8', label: 'Animals', active: 0 },
    { key: '9', label: 'Coding', active: 0},
    { key: '10', label: 'Party', active: 0},
])

I do a api call for get ACTIVE tag from my user :

useEffect(() => {
   const fetchData = async () => {
       setLoad(true)
       try {
           const result = await axios.post('/user/activetag')
           console.log(result.data.active_tag)
            setTagData({
                   // update
            })
       } catch (error) {
           console.log(error)
       }
       setLoad(false)
   }
   fetchData()
}, [])

Then the result store the active tags like this :

active_tag: Array(5)
0: {tag_id: 1, label: "Music"}
1: {tag_id: 2, label: "Sport"}
2: {tag_id: 3, label: "Dance"}
3: {tag_id: 4, label: "Cook"}
4: {tag_id: 5, label: "Video Games"}

I would like to update the tagData state and put active to 1 where the tag_id is equal to the key of tagData state, any idea ?

Full code :

import React, {useState, useEffect} from "react";
import { makeStyles } from '@material-ui/core/styles';
import Chip from '@material-ui/core/Chip';
import Paper from '@material-ui/core/Paper';
import DoneIcon from '@material-ui/icons/Done';
import axios from 'axios'
import Loading from '../../../../Loading/Loading'

const useStyles = makeStyles((theme) => ({
  // style
 })
export default function TagUser(){
const classes = useStyles();
const [load, setLoad] = useState(false)
const  [tagData, setTagData] = useState([
    { key: '1', label: 'Music', active: 0 },
    { key: '2', label: 'Sport', active: 0 },
    { key: '3', label: 'Dance', active: 0 },
    { key: '4', label: 'Cook', active: 0},
    { key: '5', label: 'Video Games', active: 0},
    { key: '6', label: 'Travel', active: 0 },
    { key: '7', label: 'Picture', active: 0 },
    { key: '8', label: 'Animals', active: 0 },
    { key: '9', label: 'Coding', active: 0},
    { key: '10', label: 'Party', active: 0},
])

useEffect(() => {
   const fetchData = async () => {
       setLoad(true)
       try {
           const result = await axios.post('/user/activetag')
           console.log(result.data)
           setTagData({
                   // update
            })
        } catch (error) {
           console.log(error)
       }
       setLoad(false)
   }
   fetchData()
}, [])


const handleDelete = (key) => {
    //delete
}
const handleSubmit = (key) => {
    //submit
}

if(load){
    return <Loading/>
} else {
return(
    <Paper variant="outlined" square component="span" className={classes.root}>
       {
           tagData.map((data) => {
               if (data.active === 0) {
                   return (
                       <li key={data.key}>
                           <Chip
                               variant="outlined"
                               color="secondary"
                               label={data.label}
                               className={classes.chip}
                               onDelete={() => handleSubmit(data.key)}
                               deleteIcon={<DoneIcon />} 
                           />
                       </li>
                   )
               } else {
                   return (
                       <li key={data.key}>
                           <Chip
                               color="secondary"
                               label={data.label}
                               className={classes.chip}
                               onDelete={() => handleDelete(data.key)}
                           />
                       </li>
                   )
               }
           })
       }
   </Paper>
  )
 }
}
1
  • Would you be open to using a small 3rd-party library if it simplifies your code? Commented Oct 23, 2020 at 16:12

2 Answers 2

1

Disclosure: I am the author of the suspense-service library used in this answer.

If you're open to using a 3rd-party library, it can significantly simplify your data-fetching logic. You won't need a load state, or a useEffect(), the component will only render when the list is ready:

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Chip from '@material-ui/core/Chip';
import Paper from '@material-ui/core/Paper';
import DoneIcon from '@material-ui/icons/Done';
import axios from 'axios';
import { createService, useService } from 'suspense-service';
import Loading from '../../../../Loading/Loading';

const defaultTags = [
  { key: '1', label: 'Music', active: 0 },
  { key: '2', label: 'Sport', active: 0 },
  { key: '3', label: 'Dance', active: 0 },
  { key: '4', label: 'Cook', active: 0},
  { key: '5', label: 'Video Games', active: 0},
  { key: '6', label: 'Travel', active: 0 },
  { key: '7', label: 'Picture', active: 0 },
  { key: '8', label: 'Animals', active: 0 },
  { key: '9', label: 'Coding', active: 0},
  { key: '10', label: 'Party', active: 0},
];

const UserActiveTags = createService(async (allTags) => {
  try {
    const result = await axios.post('/user/activetag');

    console.log(result.data.active_tag);

    const activeTags = result.data.active_tag.map((tag) => tag.tag_id);
    const activeTagsSet = new Set(activeTags);

    return allTags.map((tag) => ({
      ...tag,
      active: activeTagsSet.has(tag.key) ? 1 : 0
    }));
  } catch (error) {
    console.log(error);
    return allTags;
  }
});

export default function TagUser() {
  return (
    <UserActiveTags.Provider request={defaultTags} fallback={<Loading />}>
      <TagList />
    </UserActiveTags.Provider>
  );
}

const useStyles = makeStyles((theme) => ({
  // style
}));

function TagList() {
  const { root, chip } = useStyles();
  const tagData = useService(UserActiveTags);

  const handleDelete = (key) => {
    //delete
  };
  const handleSubmit = (key) => {
    //submit
  };

  const tagList = tagData.map(({ active, key, label }) => {
    const props = active === 0
      ? { variant: 'outlined', onDelete: () => handleSubmit(key), deleteIcon: <DoneIcon /> }
      : { variant: 'default', onDelete: () => handleDelete(key) };

    return (
      <li key={key}>
        <Chip
          color="secondary"
          label={label}
          className={chip}
          {...props}
        />
      </li>
    );
  });

  return (
    <Paper variant="outlined" square={true} component="span" className={root}>
      {tagList}
    </Paper>
  );
}

If you need tagData to be stateful, then

const tagData = useService(UserActiveTags);

needs to be updated to this:

const initialTagData = useService(UserActiveTags);
const [tagData, setTagData] = useState(initialTagData);

useEffect(() => {
  setTagData(initialTagData);
}, [initialTagData]);
Sign up to request clarification or add additional context in comments.

3 Comments

your lib seem interseting i will try it ;)
@YanDbz do your handle... functions call setTagData()? If so, I need to slightly edit my answer to accomodate that. It will only be a minor edit though.
yes he does, i only change the active to 0 at 1 or 1 to 0 again
0

I think you could something like this,

In your useEffect(),

const result = await axios.post('/user/activetag');
const filteredTags = tagData.map((e) => {
    const checkActive = result.data.some(i => i.tag_id == e.key);
    if(checkActive){
      const temp = {...e};
      temp.active = 1;
      return temp;
    }
   return e;
});

setTagData(filteredTags);

Hope that works!

3 Comments

That would cause an infinite loop because rules of hooks would require tagData to be a dependency of the useEffect() with this approach.
Nop :/, it pull al active to 1, when i log filteredTags, btw result.data.some is my result.data.active_tag.map() ?
it works too i changed result.data.some(/* /) by result.data.active_tag.find(/ */)

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.