Не могу использовать Context API при создании дерева - PullRequest
2 голосов
/ 15 апреля 2019

Я пытаюсь создать дерево и использовать контекстный 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)

Вот мой HOC для контекстного API

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.

Как я могу сделать DataTree с withFilter внутри себя? Кроме того, я не уверен, правильно ли я настраиваю контекстный API.

1 Ответ

2 голосов
/ 15 апреля 2019

Поскольку вы используете хуки, лучше использовать хуки в качестве шаблона, а не 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;
...