制作树时无法使用上下文API

时间:2019-04-15 17:52:24

标签: reactjs react-hooks

我正在尝试制作一棵树并使用上下文API,以便树的所有节点都可以调用父函数。

这是我的树的开始

<Filter>
    {dataSource.map((x, i) => {
        return <DataTree
            key={i}
            name={x.name}
            type={x.type}
            children={x.children}
        />
    })}
</Filter>

这是我的树节点

function DataTree(props) {

    const [isOpen, setIsOpen] = useState(false)

    return (
        <div className="mt-3">
            <div className="row">
                {props.children &&
                    <button className="btn-primary mr-2" onClick={() => setIsOpen(!isOpen)}>+</button>
                }
                <h5 onClick={() => props.setFilter(props.name, props.type)}>{props.name}</h5>
            </div>
            <h1>{JSON.stringify(props.filters)}</h1>
            <div className="pl-5">
                <Filter>
                    {isOpen && props.children && props.children.map((x, i) => {
                        return <DataTree
                            key={i}
                            name={x.name}
                            type={x.type}
                            children={x.children}
                        />
                    })}
                </Filter>
            </div>
        </div>
    )
}

export default withFilter(DataTree)

这是我的上下文API的HOC

const FilterContex = React.createContext()

export function Filter(props) {

    const [filters, setFilters] = useState({})

    const addToFilter = (value, name) => {
        setFilters({ ...filters, [name]: value })
    }

    return (
        <FilterContex.Provider value={{ filters, setFilter: addToFilter }}>
            {props.children}
        </FilterContex.Provider>
    )
}

export function withFilter(Component) {
    return function FilterComponent(props) {
        return (
            <FilterContex.Consumer>
                {context => <Component {...props} {...context} />}
            </FilterContex.Consumer>
        )
    }
}

问题在于,我正在渲染的DataTree内的DataTree不是withFilter的那个,所以只有树的第一个节点才具有上下文API。 / p>

如何在自身内部渲染DataTree的{​​{1}}? 另外,我不确定是否要使上下文API正常工作。

1 个答案:

答案 0 :(得分:2)

由于使用的是钩子,因此最好将钩子作为一种模式而不是HOC。因此,您的解决方案将包括使用useContext钩子来访问组件中的上下文

DataTree

function DataTree(props) {

    const [isOpen, setIsOpen] = useState(false)
    const {filters, setFilter} = useContext(FilterContex);
    return (
        <div className="mt-3">
            <div className="row">
                {props.children &&
                    <button className="btn-primary mr-2" onClick={() => setIsOpen(!isOpen)}>+</button>
                }
                <h5 onClick={() => setFilter(props.name, props.type)}>{props.name}</h5>
            </div>
            <h1>{JSON.stringify(filters)}</h1>
            <div className="pl-5">
                <Filter>
                    {isOpen && props.children && props.children.map((x, i) => {
                        return <DataTree
                            key={i}
                            name={x.name}
                            type={x.type}
                            children={x.children}
                        />
                    })}
                </Filter>
            </div>
        </div>
    )
}

export default DataTree;

过滤器API

export const FilterContex = React.createContext()

export function Filter(props) {

    const [filters, setFilters] = useState({})

    const addToFilter = (value, name) => {
        setFilters({ ...filters, [name]: value })
    }

    return (
        <FilterContex.Provider value={{ filters, setFilter: addToFilter }}>
            {props.children}
        </FilterContex.Provider>
    )
}

如果您想知道如何使用HOC实现相同的功能,则需要创建一个新的连接的DataTree组件并将其用于嵌套渲染

function DataTree(props) {

    const [isOpen, setIsOpen] = useState(false)
    return (
        <div className="mt-3">
            <div className="row">
                {props.children &&
                    <button className="btn-primary mr-2" onClick={() => setIsOpen(!isOpen)}>+</button>
                }
                <h5 onClick={() => props.setFilter(props.name, props.type)}>{props.name}</h5>
            </div>
            <h1>{JSON.stringify(props.filters)}</h1>
            <div className="pl-5">
                <Filter>
                    {isOpen && props.children && props.children.map((x, i) => {
                        return <DataTreeWithFilter
                            key={i}
                            name={x.name}
                            type={x.type}
                            children={x.children}
                        />
                    })}
                </Filter>
            </div>
        </div>
    )
}

const DataTreeWithFilter = withFilter(DataTree);
export default DataTreeWithFilter;