import React, { useContext, useEffect, useRef, useState } from 'react'
//判断受控与非受控组件的钩子
import { useAutoControlledState } from './useAutoControlledState'
//使用context可以支持各种嵌套
const SelectContext = React.createContext()
function Option({ value, children, ...rest }) {
const context = useContext(SelectContext)
if (context === undefined)
throw new Error('Select.Option must be used within Select')
const { state, setState, finalOptions, setFinalOptions } = context
//useEffect是异步的
useEffect(() => {
setFinalOptions((prev) =>
//先筛选掉再进行拼接 避免重复
prev.filter((item) => item.value !== value).concat({ value, children })
)
//由于依赖发生改变的话也会触发useEffect 所以要在他每次return的时候筛选一遍 return 是每一次都会触发的
return () =>
setFinalOptions((prev) => prev.filter((item) => item.value !== value))
}, [value, children, setFinalOptions])
// 添加选中高亮
const isActive = value === state
return (
{
if (el) {
//添加选中的高亮
if (isActive) {
el.dataset.isActive = isActive
} else {
delete el.dataset.isActive
}
}
}}
onClick={() => setState(value)}
{...rest}
>
{children}
)
}
export function Select({
options = [],
value,
defaultValue,
onChange,
//可以对options的key做一个映射
optionsMapping,
children,
...rest
}) {
const [state, setState] = useAutoControlledState({
value,
defaultValue,
onChange,
})
//options可以是简单值[‘’,‘’,‘’],也可以是对象形式的
const mappedOptions = optionsMapping
? options.map(optionsMapping)
: options.map((item) => ({
value: typeof item === 'object' ? item.value : item,
children: typeof item === 'object' ? item.children : item,
}))
// 给子组件传入一个引用 然后由子组件去修改这个引用将options传到父组件来
//一开始用的是useRef 但是useRef去改变这个引用是不会触发更新的 会导致第一次取不到值 所以改成了useState
const [finalOptions, setFinalOptions] = useState(mappedOptions)
//当前选中的值
const selected = finalOptions.find((item) => item.value === state)
return (
{
state,
setState,
finalOptions,
setFinalOptions,
}}
>
{selected?.children}
{mappedOptions.map((item) => (
))}
{children}
)
}
Select.Option = Option
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)