Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/453.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 当子组件通过父组件进行筛选时,如何维护子组件的状态?_Javascript_Reactjs_React Hooks_Create React App_React State Management - Fatal编程技术网

Javascript 当子组件通过父组件进行筛选时,如何维护子组件的状态?

Javascript 当子组件通过父组件进行筛选时,如何维护子组件的状态?,javascript,reactjs,react-hooks,create-react-app,react-state-management,Javascript,Reactjs,React Hooks,Create React App,React State Management,我正在使用create-react-app构建一个小应用程序,以提高我的react知识,但现在仍然坚持状态管理 应用程序通过父组件上的JSON数据进行映射,并将6张“图像卡”打印为子组件,其中包含一组“标记”来描述它,以及作为道具传递的其他数据(url、标题等) 每个卡都有一个输入,您可以在现有列表中添加更多标签 在父组件上有一个输入,可用于通过标签过滤卡片。 (仅过滤默认标签,而不是新添加到卡中的标签) 我试图实现的是在过滤每张卡时保持其状态。当前发生的情况是,如果我向卡片添加新标签并使用多个

我正在使用create-react-app构建一个小应用程序,以提高我的react知识,但现在仍然坚持状态管理

应用程序通过父组件上的JSON数据进行映射,并将6张“图像卡”打印为子组件,其中包含一组“标记”来描述它,以及作为道具传递的其他数据(url、标题等)

每个卡都有一个输入,您可以在现有列表中添加更多标签

在父组件上有一个输入,可用于通过标签过滤卡片。 (仅过滤默认标签,而不是新添加到卡中的标签)

我试图实现的是在过滤每张卡时保持其状态。当前发生的情况是,如果我向卡片添加新标签并使用多个标签进行过滤,则只有初始过滤的卡片包含新标签,其余的将使用默认标签重新渲染。谁能告诉我哪里出了问题,谢谢

我的项目也可以克隆,如果它使事情更容易

data.json示例

{
    "assets": [
        {
            "url": "https://images.unsplash.com/photo-1583450119183-66febdb2f409?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=200&ixlib=rb-1.2.1&q=80&w=200",
            "title": "Car",
            "tags": [
                { "id": "USA", "text": "USA" },
                { "id": "Car", "text": "Car" }
            ],
            "suggestions": [
                { "id": "Colour", "text": "Colour" },
                { "id": "Motor", "text": "Motor" },
                { "id": "Engineering", "text": "Engineering" }
            ]
        },
        {
            "url": "https://images.unsplash.com/photo-1582996269871-dad1e4adbbc7?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=200&ixlib=rb-1.2.1&q=80&w=200",
            "title": "Plate",
            "tags": [
                { "id": "Art", "text": "Art" },
                { "id": "Wood", "text": "Wood" },
                { "id": "Spoon", "text": "Spoon" }
            ],
            "suggestions": [
                { "id": "Cutlery", "text": "Cutlery" },
                { "id": "Serenity", "text": "Serenity" }
            ]
        }
    ]
}
父组件

import React, {useState} from 'react';
import Item from './Item'
import data from '../../data.json';

import './Assets.scss'

function Assets() {
    const [state, updateMethod] = useState({tag: "", tags: []});

    const printList = () => {
        //if tag in filter has been added        
        if (state.tags.length > 0) {
            return data.assets.map(elem => {
                //extract ids from obj into array
                const dataArr = elem.tags.map(item => item.id);
                const stateArr = state.tags.map(item => item.id);

                //check if tag is found in asset
                const doesTagExist = stateArr.some(item => dataArr.includes(item));
                //if found, return asset 
                if (doesTagExist) return <Item key={elem.title} data={elem} />;
            })
        } else {
            return data.assets.map(elem => (<Item key={elem.title} data={elem} /> ));
        }
    };

    const handleClick = () => {
        const newTag = {id: state.tag, text: state.tag};
        const copy = [...state.tags, newTag];

        if (state.tag !== "") updateMethod({tag: "", tags: copy});
    }

    const handleChange = e => updateMethod({tag: e.target.value, tags: state.tags});

    const handleDelete = i => {
        const copy = [...state.tags];
        let removed = copy.filter((elem, indx) => indx !== i);

        updateMethod({tag: state.tag, tags: removed});
    }

    return (
        <div className="assets">
            <div className="asset__filter">
                <h3>Add tags to filter</h3>
                <ul className="asset__tag-list">
                    {state.tags.map((elem, i) => (
                        <li className="asset__tag" key={`${elem.id}_${i}`} >
                            {elem.text}

                            <button className="asset__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag}
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="asset__tag-input"
                />

                <button className="asset__btn" onClick={handleClick}>Add</button>
            </div>

            <div className="item__list-holder">
                {printList()}
            </div>
        </div>
    );  
}

export default Assets;
import React, {useState, useEffect} from 'react';

function Item(props) {
    const [state, updateMethod] = useState({tag: "", tags: []});

    const handleClick = () => {
        //create new tag from state
        const newTag = {id: state.tag, text: state.tag};
        //create copy of state and add new tag
        const copy = [...state.tags, newTag];
        //if state is not empty update state with new tags
        if (state.tag !== "") updateMethod({tag: "", tags: copy});
    }

    const handleChange = e => updateMethod({tag: e.target.value, tags: state.tags});

    const handleDelete = i => {
        //copy state
        const copy = [...state.tags];
        //filter out tag to be deleted
        let removed = copy.filter((elem, indx) => indx !== i);
        //add updated tags to state
        updateMethod({tag: state.tag, tags: removed});
    }

    useEffect(() => {
        console.log("item rendered");
        //when first rendered, add default tags from json to state
        updateMethod({tag: "", tags: props.data.tags});
    }, [props.data.tags]);

    const assets = props.data;

    return (
        <div className="item">
            <img src={assets.url} alt="assets.title"/>
            <h1 className="item__title">{assets.title}</h1>

            <div className="item__tag-holder">
                <ul className="item__tag-list">
                    {state.tags.map((elem, i) => (
                        <li className="item__tag" key={`${elem.id}_${i}`} >
                            {elem.text}
                            <button className="item__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag} 
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="item__tag-input"
                />

                <button className="item__btn" onClick={handleClick}>Add</button>
            </div>
        </div>
    );
}

export default Item;
import React, {useState} from 'react';
import Item from './Item'
import data from '../../data.json';

import './Assets.scss'

function Assets() {
    const [state, updateMethod] = useState({tag: "", tags: []});

    const [childrenTags, setChildrenTags] = useState(data.assets.map(elem => elem.tags));

    const addChildrenTag = (index) => (tag) => {
        let newTags = Array.from(childrenTags)
        newTags[index] = [...newTags[index], tag]

        setChildrenTags(newTags)
    }

    const removeChildrenTag = (index) => (i) => {
        let newTags = Array.from(childrenTags)
        newTags[index] = newTags[index].filter((elem, indx) => indx !== i)

        setChildrenTags(newTags)
    }

    const printList = () => {
        //if tag in filter has been added        
        if (state.tags.length > 0) {
            return data.assets.map((elem, index) => {
                //extract ids from obj into array
                const dataArr = elem.tags.map(item => item.id);
                const stateArr = state.tags.map(item => item.id);

                //check if tag is found in asset
                const doesTagExist = stateArr.some(item => dataArr.includes(item));
                //if found, return asset 
                if (doesTagExist) 
                    return (
                        <Item 
                            key={elem.title} 
                            data={elem} 
                            customTags={childrenTags[index]} 
                            addCustomTag={addChildrenTag(index)}
                            removeCustomTag={removeChildrenTag(index)}
                        />
                    )
            })
        } else {
            return data.assets.map((elem, index) => (
                <Item 
                    key={elem.title} 
                    data={elem} 
                    customTags={childrenTags[index]} 
                    addCustomTag={addChildrenTag(index)}
                    removeCustomTag={removeChildrenTag(index)}
                />
            ));
        }
    };

    const handleClick = () => {
        const newTag = {id: state.tag, text: state.tag};
        const copy = [...state.tags, newTag];

        if (state.tag !== "") updateMethod({tag: "", tags: copy});
    }

    const handleChange = e => updateMethod({tag: e.target.value, tags: state.tags});

    const handleDelete = i => {
        const copy = [...state.tags];
        let removed = copy.filter((elem, indx) => indx !== i);

        updateMethod({tag: state.tag, tags: removed});
    }

    return (
        <div className="assets">
            <div className="asset__filter">
                <h3>Add tags to filter</h3>
                <ul className="asset__tag-list">
                    {state.tags.map((elem, i) => (
                        <li className="asset__tag" key={`${elem.id}_${i}`} >
                            {elem.text}

                            <button className="asset__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag}
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="asset__tag-input"
                />

                <button className="asset__btn" onClick={handleClick}>Add</button>
            </div>

            <div className="item__list-holder">
                {printList()}
            </div>
        </div>
    );  
}

export default Assets;
import React, {useState, useEffect} from 'react';

function Item(props) {
    const [state, updateMethod] = useState({tag: ""});
    cosnst tags = props.customTags
    cosnst addCustomTag = props.addCustomTag
    cosnst removeCustomTag = props.removeCustomTag

    const handleClick = () => {
        if (state.tag !== "") addCustomTag(state.tag);
    }

    const handleChange = e => updateMethod({tag: e.target.value});

    const handleDelete = i => {
        removeCustomTag(i);
    }

    const assets = props.data;

    return (
        <div className="item">
            <img src={assets.url} alt="assets.title"/>
            <h1 className="item__title">{assets.title}</h1>

            <div className="item__tag-holder">
                <ul className="item__tag-list">
                    {tags.map((elem, i) => (
                        <li className="item__tag" key={`${elem.id}_${i}`} >
                            {elem.text}
                            <button className="item__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag} 
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="item__tag-input"
                />

                <button className="item__btn" onClick={handleClick}>Add</button>
            </div>
        </div>
    );
}

export default Item;
import React,{useState}来自“React”;
从“./Item”导入项目
从“../../data.json”导入数据;
导入“./Assets.scss”
功能资产(){
const[state,updateMethod]=useState({tag:,tags:[]);
常量打印列表=()=>{
//如果已添加过滤器中的标记
如果(state.tags.length>0){
返回data.assets.map(elem=>{
//将ID从obj提取到数组中
constdataarr=elem.tags.map(item=>item.id);
const stateArr=state.tags.map(item=>item.id);
//检查是否在资产中找到标记
const doesTagExist=stateArr.some(item=>dataArr.includes(item));
//如果找到,则返回资产
如果(不存在)返回;
})
}否则{
返回data.assets.map(elem=>());
}
};
常量handleClick=()=>{
const newTag={id:state.tag,text:state.tag};
const copy=[…state.tags,newTag];
if(state.tag!==“”)updateMethod({tag:,tags:copy});
}
const-handleChange=e=>updateMethod({tag:e.target.value,tags:state.tags});
常数handleDelete=i=>{
constcopy=[…state.tags];
let removed=copy.filter((elem,indx)=>indx!==i);
updateMethod({tag:state.tag,tags:removed});
}
返回(
将标记添加到过滤器
    {state.tags.map((elem,i)=>(
  • {elem.text} handleDelete(i)}>x
  • ))}
添加 {printList()} ); } 出口违约资产;
子组件

import React, {useState} from 'react';
import Item from './Item'
import data from '../../data.json';

import './Assets.scss'

function Assets() {
    const [state, updateMethod] = useState({tag: "", tags: []});

    const printList = () => {
        //if tag in filter has been added        
        if (state.tags.length > 0) {
            return data.assets.map(elem => {
                //extract ids from obj into array
                const dataArr = elem.tags.map(item => item.id);
                const stateArr = state.tags.map(item => item.id);

                //check if tag is found in asset
                const doesTagExist = stateArr.some(item => dataArr.includes(item));
                //if found, return asset 
                if (doesTagExist) return <Item key={elem.title} data={elem} />;
            })
        } else {
            return data.assets.map(elem => (<Item key={elem.title} data={elem} /> ));
        }
    };

    const handleClick = () => {
        const newTag = {id: state.tag, text: state.tag};
        const copy = [...state.tags, newTag];

        if (state.tag !== "") updateMethod({tag: "", tags: copy});
    }

    const handleChange = e => updateMethod({tag: e.target.value, tags: state.tags});

    const handleDelete = i => {
        const copy = [...state.tags];
        let removed = copy.filter((elem, indx) => indx !== i);

        updateMethod({tag: state.tag, tags: removed});
    }

    return (
        <div className="assets">
            <div className="asset__filter">
                <h3>Add tags to filter</h3>
                <ul className="asset__tag-list">
                    {state.tags.map((elem, i) => (
                        <li className="asset__tag" key={`${elem.id}_${i}`} >
                            {elem.text}

                            <button className="asset__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag}
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="asset__tag-input"
                />

                <button className="asset__btn" onClick={handleClick}>Add</button>
            </div>

            <div className="item__list-holder">
                {printList()}
            </div>
        </div>
    );  
}

export default Assets;
import React, {useState, useEffect} from 'react';

function Item(props) {
    const [state, updateMethod] = useState({tag: "", tags: []});

    const handleClick = () => {
        //create new tag from state
        const newTag = {id: state.tag, text: state.tag};
        //create copy of state and add new tag
        const copy = [...state.tags, newTag];
        //if state is not empty update state with new tags
        if (state.tag !== "") updateMethod({tag: "", tags: copy});
    }

    const handleChange = e => updateMethod({tag: e.target.value, tags: state.tags});

    const handleDelete = i => {
        //copy state
        const copy = [...state.tags];
        //filter out tag to be deleted
        let removed = copy.filter((elem, indx) => indx !== i);
        //add updated tags to state
        updateMethod({tag: state.tag, tags: removed});
    }

    useEffect(() => {
        console.log("item rendered");
        //when first rendered, add default tags from json to state
        updateMethod({tag: "", tags: props.data.tags});
    }, [props.data.tags]);

    const assets = props.data;

    return (
        <div className="item">
            <img src={assets.url} alt="assets.title"/>
            <h1 className="item__title">{assets.title}</h1>

            <div className="item__tag-holder">
                <ul className="item__tag-list">
                    {state.tags.map((elem, i) => (
                        <li className="item__tag" key={`${elem.id}_${i}`} >
                            {elem.text}
                            <button className="item__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag} 
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="item__tag-input"
                />

                <button className="item__btn" onClick={handleClick}>Add</button>
            </div>
        </div>
    );
}

export default Item;
import React, {useState} from 'react';
import Item from './Item'
import data from '../../data.json';

import './Assets.scss'

function Assets() {
    const [state, updateMethod] = useState({tag: "", tags: []});

    const [childrenTags, setChildrenTags] = useState(data.assets.map(elem => elem.tags));

    const addChildrenTag = (index) => (tag) => {
        let newTags = Array.from(childrenTags)
        newTags[index] = [...newTags[index], tag]

        setChildrenTags(newTags)
    }

    const removeChildrenTag = (index) => (i) => {
        let newTags = Array.from(childrenTags)
        newTags[index] = newTags[index].filter((elem, indx) => indx !== i)

        setChildrenTags(newTags)
    }

    const printList = () => {
        //if tag in filter has been added        
        if (state.tags.length > 0) {
            return data.assets.map((elem, index) => {
                //extract ids from obj into array
                const dataArr = elem.tags.map(item => item.id);
                const stateArr = state.tags.map(item => item.id);

                //check if tag is found in asset
                const doesTagExist = stateArr.some(item => dataArr.includes(item));
                //if found, return asset 
                if (doesTagExist) 
                    return (
                        <Item 
                            key={elem.title} 
                            data={elem} 
                            customTags={childrenTags[index]} 
                            addCustomTag={addChildrenTag(index)}
                            removeCustomTag={removeChildrenTag(index)}
                        />
                    )
            })
        } else {
            return data.assets.map((elem, index) => (
                <Item 
                    key={elem.title} 
                    data={elem} 
                    customTags={childrenTags[index]} 
                    addCustomTag={addChildrenTag(index)}
                    removeCustomTag={removeChildrenTag(index)}
                />
            ));
        }
    };

    const handleClick = () => {
        const newTag = {id: state.tag, text: state.tag};
        const copy = [...state.tags, newTag];

        if (state.tag !== "") updateMethod({tag: "", tags: copy});
    }

    const handleChange = e => updateMethod({tag: e.target.value, tags: state.tags});

    const handleDelete = i => {
        const copy = [...state.tags];
        let removed = copy.filter((elem, indx) => indx !== i);

        updateMethod({tag: state.tag, tags: removed});
    }

    return (
        <div className="assets">
            <div className="asset__filter">
                <h3>Add tags to filter</h3>
                <ul className="asset__tag-list">
                    {state.tags.map((elem, i) => (
                        <li className="asset__tag" key={`${elem.id}_${i}`} >
                            {elem.text}

                            <button className="asset__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag}
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="asset__tag-input"
                />

                <button className="asset__btn" onClick={handleClick}>Add</button>
            </div>

            <div className="item__list-holder">
                {printList()}
            </div>
        </div>
    );  
}

export default Assets;
import React, {useState, useEffect} from 'react';

function Item(props) {
    const [state, updateMethod] = useState({tag: ""});
    cosnst tags = props.customTags
    cosnst addCustomTag = props.addCustomTag
    cosnst removeCustomTag = props.removeCustomTag

    const handleClick = () => {
        if (state.tag !== "") addCustomTag(state.tag);
    }

    const handleChange = e => updateMethod({tag: e.target.value});

    const handleDelete = i => {
        removeCustomTag(i);
    }

    const assets = props.data;

    return (
        <div className="item">
            <img src={assets.url} alt="assets.title"/>
            <h1 className="item__title">{assets.title}</h1>

            <div className="item__tag-holder">
                <ul className="item__tag-list">
                    {tags.map((elem, i) => (
                        <li className="item__tag" key={`${elem.id}_${i}`} >
                            {elem.text}
                            <button className="item__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag} 
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="item__tag-input"
                />

                <button className="item__btn" onClick={handleClick}>Add</button>
            </div>
        </div>
    );
}

export default Item;
import React,{useState,useffect}来自“React”;
功能项目(道具){
const[state,updateMethod]=useState({tag:,tags:[]);
常量handleClick=()=>{
//从状态创建新标记
const newTag={id:state.tag,text:state.tag};
//创建状态副本并添加新标记
const copy=[…state.tags,newTag];
//如果状态不为空,则使用新标记更新状态
if(state.tag!==“”)updateMethod({tag:,tags:copy});
}
const-handleChange=e=>updateMethod({tag:e.target.value,tags:state.tags});
常数handleDelete=i=>{
//复制状态
constcopy=[…state.tags];
//筛选出要删除的标记
let removed=copy.filter((elem,indx)=>indx!==i);
//将更新的标记添加到状态
updateMethod({tag:state.tag,tags:removed});
}
useffect(()=>{
控制台日志(“呈现的项目”);
//首次呈现时,将默认标记从json添加到状态
updateMethod({tag:,tags:props.data.tags});
},[props.data.tags]);
常量资产=道具数据;
返回(
{assets.title}
    {state.tags.map((elem,i)=>(
  • {elem.text} handleDelete(i)}>x
  • ))}
添加 ); } 导出默认项;
您面临的问题是,消失的卡被卸载,这意味着它们的状态丢失。最好的解决方案是将添加到卡中的新自定义标记保留在父组件中,因此无论卡是否已装入,它都是持久的。以下是修改后的文件:

父组件

import React, {useState} from 'react';
import Item from './Item'
import data from '../../data.json';

import './Assets.scss'

function Assets() {
    const [state, updateMethod] = useState({tag: "", tags: []});

    const printList = () => {
        //if tag in filter has been added        
        if (state.tags.length > 0) {
            return data.assets.map(elem => {
                //extract ids from obj into array
                const dataArr = elem.tags.map(item => item.id);
                const stateArr = state.tags.map(item => item.id);

                //check if tag is found in asset
                const doesTagExist = stateArr.some(item => dataArr.includes(item));
                //if found, return asset 
                if (doesTagExist) return <Item key={elem.title} data={elem} />;
            })
        } else {
            return data.assets.map(elem => (<Item key={elem.title} data={elem} /> ));
        }
    };

    const handleClick = () => {
        const newTag = {id: state.tag, text: state.tag};
        const copy = [...state.tags, newTag];

        if (state.tag !== "") updateMethod({tag: "", tags: copy});
    }

    const handleChange = e => updateMethod({tag: e.target.value, tags: state.tags});

    const handleDelete = i => {
        const copy = [...state.tags];
        let removed = copy.filter((elem, indx) => indx !== i);

        updateMethod({tag: state.tag, tags: removed});
    }

    return (
        <div className="assets">
            <div className="asset__filter">
                <h3>Add tags to filter</h3>
                <ul className="asset__tag-list">
                    {state.tags.map((elem, i) => (
                        <li className="asset__tag" key={`${elem.id}_${i}`} >
                            {elem.text}

                            <button className="asset__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag}
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="asset__tag-input"
                />

                <button className="asset__btn" onClick={handleClick}>Add</button>
            </div>

            <div className="item__list-holder">
                {printList()}
            </div>
        </div>
    );  
}

export default Assets;
import React, {useState, useEffect} from 'react';

function Item(props) {
    const [state, updateMethod] = useState({tag: "", tags: []});

    const handleClick = () => {
        //create new tag from state
        const newTag = {id: state.tag, text: state.tag};
        //create copy of state and add new tag
        const copy = [...state.tags, newTag];
        //if state is not empty update state with new tags
        if (state.tag !== "") updateMethod({tag: "", tags: copy});
    }

    const handleChange = e => updateMethod({tag: e.target.value, tags: state.tags});

    const handleDelete = i => {
        //copy state
        const copy = [...state.tags];
        //filter out tag to be deleted
        let removed = copy.filter((elem, indx) => indx !== i);
        //add updated tags to state
        updateMethod({tag: state.tag, tags: removed});
    }

    useEffect(() => {
        console.log("item rendered");
        //when first rendered, add default tags from json to state
        updateMethod({tag: "", tags: props.data.tags});
    }, [props.data.tags]);

    const assets = props.data;

    return (
        <div className="item">
            <img src={assets.url} alt="assets.title"/>
            <h1 className="item__title">{assets.title}</h1>

            <div className="item__tag-holder">
                <ul className="item__tag-list">
                    {state.tags.map((elem, i) => (
                        <li className="item__tag" key={`${elem.id}_${i}`} >
                            {elem.text}
                            <button className="item__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag} 
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="item__tag-input"
                />

                <button className="item__btn" onClick={handleClick}>Add</button>
            </div>
        </div>
    );
}

export default Item;
import React, {useState} from 'react';
import Item from './Item'
import data from '../../data.json';

import './Assets.scss'

function Assets() {
    const [state, updateMethod] = useState({tag: "", tags: []});

    const [childrenTags, setChildrenTags] = useState(data.assets.map(elem => elem.tags));

    const addChildrenTag = (index) => (tag) => {
        let newTags = Array.from(childrenTags)
        newTags[index] = [...newTags[index], tag]

        setChildrenTags(newTags)
    }

    const removeChildrenTag = (index) => (i) => {
        let newTags = Array.from(childrenTags)
        newTags[index] = newTags[index].filter((elem, indx) => indx !== i)

        setChildrenTags(newTags)
    }

    const printList = () => {
        //if tag in filter has been added        
        if (state.tags.length > 0) {
            return data.assets.map((elem, index) => {
                //extract ids from obj into array
                const dataArr = elem.tags.map(item => item.id);
                const stateArr = state.tags.map(item => item.id);

                //check if tag is found in asset
                const doesTagExist = stateArr.some(item => dataArr.includes(item));
                //if found, return asset 
                if (doesTagExist) 
                    return (
                        <Item 
                            key={elem.title} 
                            data={elem} 
                            customTags={childrenTags[index]} 
                            addCustomTag={addChildrenTag(index)}
                            removeCustomTag={removeChildrenTag(index)}
                        />
                    )
            })
        } else {
            return data.assets.map((elem, index) => (
                <Item 
                    key={elem.title} 
                    data={elem} 
                    customTags={childrenTags[index]} 
                    addCustomTag={addChildrenTag(index)}
                    removeCustomTag={removeChildrenTag(index)}
                />
            ));
        }
    };

    const handleClick = () => {
        const newTag = {id: state.tag, text: state.tag};
        const copy = [...state.tags, newTag];

        if (state.tag !== "") updateMethod({tag: "", tags: copy});
    }

    const handleChange = e => updateMethod({tag: e.target.value, tags: state.tags});

    const handleDelete = i => {
        const copy = [...state.tags];
        let removed = copy.filter((elem, indx) => indx !== i);

        updateMethod({tag: state.tag, tags: removed});
    }

    return (
        <div className="assets">
            <div className="asset__filter">
                <h3>Add tags to filter</h3>
                <ul className="asset__tag-list">
                    {state.tags.map((elem, i) => (
                        <li className="asset__tag" key={`${elem.id}_${i}`} >
                            {elem.text}

                            <button className="asset__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag}
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="asset__tag-input"
                />

                <button className="asset__btn" onClick={handleClick}>Add</button>
            </div>

            <div className="item__list-holder">
                {printList()}
            </div>
        </div>
    );  
}

export default Assets;
import React, {useState, useEffect} from 'react';

function Item(props) {
    const [state, updateMethod] = useState({tag: ""});
    cosnst tags = props.customTags
    cosnst addCustomTag = props.addCustomTag
    cosnst removeCustomTag = props.removeCustomTag

    const handleClick = () => {
        if (state.tag !== "") addCustomTag(state.tag);
    }

    const handleChange = e => updateMethod({tag: e.target.value});

    const handleDelete = i => {
        removeCustomTag(i);
    }

    const assets = props.data;

    return (
        <div className="item">
            <img src={assets.url} alt="assets.title"/>
            <h1 className="item__title">{assets.title}</h1>

            <div className="item__tag-holder">
                <ul className="item__tag-list">
                    {tags.map((elem, i) => (
                        <li className="item__tag" key={`${elem.id}_${i}`} >
                            {elem.text}
                            <button className="item__tag-del" onClick={() => handleDelete(i)}>x</button>
                        </li>
                    ))}
                </ul>

                <input 
                    type="text" 
                    value={state.tag} 
                    onChange={handleChange} 
                    placeholder="Enter new tag" 
                    className="item__tag-input"
                />

                <button className="item__btn" onClick={handleClick}>Add</button>
            </div>
        </div>
    );
}

export default Item;
import React,{useState}来自“React”;
从“./Item”导入项目
从“../../data.json”导入数据;
导入“./Assets.scss”
功能资产(){
const[state,updateMethod]=useState({tag:,tags:[]);
const[childrenTags,setChildrenTags]=useState(data.assets.map(elem=>elem.tags));
const addChildrenTag=(索引)=>(标记)=>{
设newTags=Array.from(childrenTags)
新标签[index]=[…新标签[index],标签]
setChildrenTags(新标签)
}
const removeChildrenTag=(索引)=>(i)=>{
设newTags=Array.from(childrenTags)
newTags[index]=newTags[index]。过滤器((elem,indx)=>indx!==i)
setChildrenTags(新标签)
}
常量打印列表=()=>{
//如果已添加过滤器中的标记
如果(state.tags.length>0){
返回data.assets.map((元素,索引)=>{
//从obj中提取id