簡體   English   中英

為什么我的 React 組件在按 useState() 控制的值進行過濾時顯示不正確的數據?

[英]Why does my React component display incorrect data when filtering by values controlled by useState()?

我有一個我想傳遞給 map function 的對象列表,它將每個 object 作為道具傳遞給要渲染的組件。

我有一個菜單並單擊每個項目調用 setActiveItem() 更新由 useState 掛鈎管理的 activeItem。

我正在嘗試根據此 activeItem 值過濾對象列表。 我已經創建了一個試圖復制問題的基本案例,但我的基本案例完美無缺,盡管它至少可以澄清我正在嘗試做的事情,它是:

import React, { useState } from 'react';
import { Menu } from 'semantic-ui-react';

const [ALL, NUMBER, LETTER] = ['All', 'Number', 'Letter'];
const data = [
  {
    tags: [ALL, NUMBER],
    value: '1'
  },
  {
    tags: [ALL, LETTER],
    value: 'a'
  },
  {
    tags: [ALL, NUMBER],
    value: '2'
  },
  {
    tags: [ALL, LETTER],
    value: 'b'
  },
  {
    tags: [ALL, NUMBER],
    value: '3'
  },
  {
    tags: [ALL, LETTER],
    value: 'c'
  },
  {
    tags: [ALL, NUMBER],
    value: '4'
  },
  {
    tags: [ALL, LETTER],
    value: 'd'
  }
];

const renderData = (allValues, filterTag) => {
  let filteredList = allValues.filter(val => {
    return val['tags'].includes(filterTag);
  });

  return (
    <div>
      {filteredList.map(object_ => {
        return object_.value;
      })}
    </div>
  );
};

const BaseCase = props => {
  const [activeItem, setActiveItem] = useState(ALL);
  return (
    <div>
      <Menu inverted stackable fluid widths={4}>
        <Menu.Item
          name={ALL}
          active={activeItem === ALL}
          onClick={(e, { name }) => setActiveItem(name)}
        />
        <Menu.Item
          name={NUMBER}
          active={activeItem === NUMBER}
          onClick={(e, { name }) => setActiveItem(name)}
        />
        <Menu.Item
          name={LETTER}
          active={activeItem === LETTER}
          onClick={(e, { name }) => setActiveItem(name)}
        />
      </Menu>
      <div>{renderData(data, activeItem)}</div>
    </div>
  );
};

export default BaseCase;

單擊數字僅顯示數字,其他一切都按預期工作。 現在我的組件不起作用。 我將數據放在一個單獨的文件中,如下所示:

import { BASH, DATA_SCIENCE, WEB_DEV, ALL } from '../constants';
const data = [
  {
    tags: [ALL],
    title: 'Concussion App for Athletes',
     .
     .
     .
  },
  {
    tags: [DATA_SCIENCE, ALL],
    title: 'Deep Learning: Exploring Car Value with an ANN',
    ...
  },
  .
  .
  .
];
export default data;

這是我的組件。 我嘗試了一些注釋掉的代碼,但這也顯示了不正確的組件。

import React, { useState } from 'react';
import ProjectCardContainer from '../../containers/ProjectCardContainer';
import { Menu } from 'semantic-ui-react';
import { ALL, BASH, DATA_SCIENCE, WEB_DEV } from './constants';
import data from './project_data';
import './Projects.scss';

const styles = {
  container: {
    display: 'flex',
    justifyContent: 'space-around'
  },
  columns: {
    display: 'flex',
    flexDirection: 'column',
    marginTop: '11px'
  }
};

const renderColumn = (projectList, filterTag) => {
  let projects = projectList.filter(proj => {
    return proj['tags'].includes(filterTag);
  });

  return (
    <div style={styles.columns}>
      {projects.map(project => {
        return <ProjectCardContainer project={project} />;
      })}
    </div>
  );
};

const Projects = () => {
  const [activeItem, setActiveItem] = useState(ALL);

//   const [, updateState] = React.useState();
//   const forceUpdate = useCallback(() => updateState({}), []);

//   useEffect(() => {
//     setTimeout(forceUpdate, 100);
//   }, [activeItem]);

  return (
    <div>
      <div className='second-nav-container'>
        <Menu inverted stackable fluid widths={4}>
          <Menu.Item
            name={ALL}
            active={activeItem === ALL}
            onClick={(e, { name }) => setActiveItem(name)}
          />
          <Menu.Item
            name={WEB_DEV}
            active={activeItem === WEB_DEV}
            onClick={(e, { name }) => setActiveItem(name)}
          />
          <Menu.Item
            name={DATA_SCIENCE}
            active={activeItem === DATA_SCIENCE}
            onClick={(e, { name }) => setActiveItem(name)}
          />
          <Menu.Item
            name={BASH}
            active={activeItem === BASH}
            onClick={(e, { name }) => setActiveItem(name)}
          />
        </Menu>
      </div>
      <div style={styles.container}>{renderColumn(data, activeItem)}</div>
    </div>
  );
};

export default Projects;

基本上,渲染的組件列表通常不正確,除非刷新頁面並使用 useState() 的默認值。 從菜單中選擇不會顯示正確類別的組件。

我認為問題在於渲染 function 在 activeItem 更新之前被調用,但我不確定如何解決該問題。 我對使用鈎子有點陌生,但這似乎是一個必須經常出現的問題。

任何人有任何想法如何使用這樣的菜單來過濾數據,然后只顯示基於過濾數據的特定組件?

我認為我們不需要過多地處理復雜的 state 管理。 我更新了基本案例以滿足您的需求:

常量.js:

export const [ALL, DATA_SCIENCE, WEB_DEV, BASH] = ['All', 'DATA_SCIENCE', 'WEB_DEV', 'BASH'];

data.js:從'./Constants'導入{ALL,DATA_SCIENCE,WEB_DEV,BASH};

const data = [
    {
        tags: [ALL],
        title: 'Concussion App for Athletes',
      },
    {
        tags: [DATA_SCIENCE, ALL],
        title: 'Deep Learning: Exploring Car Value with an ANN',
    },
    {
        tags: [BASH, ALL],
        title: 'Bash 101'
    },
    {
        tags: [WEB_DEV, ALL],
        title: 'Web Development Book'
    },
    {
        tags: [WEB_DEV, ALL],
        title: 'Fundamentals of web design'
    }
]

export default {data};

BaseCase.js:

import React, { useState } from 'react';
import { Menu } from 'semantic-ui-react';
import data from './data';
import {ALL, DATA_SCIENCE, WEB_DEV, BASH} from './Constants';


const renderData = (allValues, filterTag) => {

  let filteredList = Object.values(allValues.data).filter(val => {
    return val['tags'].includes(filterTag);
  });

  return (
    <div>
      {filteredList.map(object_ => {
        return <p>{object_.title}</p>;
      })}
    </div>
  );
};

const BaseCase = props => {

const [activeItem, setActiveItem] = useState(ALL);

const newData = data;

  return (
    <div>
      <Menu inverted stackable fluid widths={4}>
        <Menu.Item
          name={ALL}
          active={activeItem === ALL}
          onClick={(e, { name }) => setActiveItem(name)}
        />
        <Menu.Item
          name={DATA_SCIENCE}
          active={activeItem === DATA_SCIENCE}
          onClick={(e, { name }) => setActiveItem(name)}
        />
        <Menu.Item
          name={WEB_DEV}
          active={activeItem === WEB_DEV}
          onClick={(e, { name }) => setActiveItem(name)}
        />
        <Menu.Item
          name={BASH}
          active={activeItem === BASH}
          onClick={(e, { name }) => setActiveItem(name)}
        />
      </Menu>
      <div>{renderData(newData, activeItem)}</div>
    </div>
  );
};

export default BaseCase;

return <p>{object_.title}</p>; 渲染出您的組件,例如<ProjectCardContainer project={object_} />

最后的問題是我在渲染組件列表時沒有提供唯一的鍵。 解決方案是提供一個唯一的密鑰,如下所示:

const renderColumn = (projectList, filterTag) => {
  let projects = projectList.filter(proj => {
    return proj['tags'].includes(filterTag);
  });

  return (
    <div style={styles.columns}>
      {projects.map(project => {
        return <ProjectCardContainer key={project.title} project={project} />;
      })}
    </div>
  );
};

就我而言,我知道標題將是獨一無二的,所以這是可行的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM