【问题标题】:Updating state array of objects from api call从 api 调用更新对象的状态数组
【发布时间】:2021-02-06 17:21:14
【问题描述】:

嘿,让我解释一下我的问题,我有一个名为 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},
])

我通过 api 调用从我的用户那里获取 ACTIVE 标记:

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()
}, [])

然后结果像这样存储活动标签:

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"}

我想更新 tagData 状态并将 active 设置为 1,其中 tag_id 等于 tagData 状态的键,知道吗?

完整代码:

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>
  )
 }
}

【问题讨论】:

  • 如果它可以简化您的代码,您是否愿意使用小型 3rd-party 库?

标签: javascript arrays reactjs axios react-hooks


【解决方案1】:

Disclosure:我是此答案中使用的suspense-service 库的作者。

如果您愿意使用第 3 方库,它可以显着简化您的数据获取逻辑。您不需要load 状态或useEffect(),组件只会在列表准备好时呈现:

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>
  );
}

如果你需要tagData 是有状态的,那么

const tagData = useService(UserActiveTags);

需要更新到这个:

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

useEffect(() => {
  setTagData(initialTagData);
}, [initialTagData]);

【讨论】:

  • 你的库看起来很有趣,我会试试看;)
  • @YanDbz 你的handle... 函数调用setTagData() 吗?如果是这样,我需要稍微编辑我的答案以适应它。不过,这只是一个小改动。
  • 是的,他这样做了,我只在 1 时将 active 更改为 0 或再次将 1 更改为 0
【解决方案2】:

我认为你可以这样,

在你的 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);

希望有效!

【讨论】:

  • 这将导致无限循环,因为使用这种方法,挂钩规则将要求 tagData 成为 useEffect() 的依赖项。
  • Nop :/,当我记录过滤标签时,它会将 al 激活到 1,顺便说一句,result.data.some 是我的 result.data.active_tag.map()?
  • 它也可以工作,我将 result.data.some(/* /) 更改为 result.data.active_tag.find(/ */)
猜你喜欢
  • 2020-07-01
  • 2022-01-06
  • 1970-01-01
  • 1970-01-01
  • 2016-10-06
  • 1970-01-01
  • 1970-01-01
  • 2018-07-01
  • 2020-10-21
相关资源
最近更新 更多