首页 > 解决方案 > 我在我的应用程序中使用带有 useContext 和 useReducer 的 typescript 使用 React,但由于某种原因,单击不会触发调度

问题描述

我有两个列表显示为来自一个初始对象列表的卡片。这个想法是在单击星号按钮时更改每个卡片列表项目中的值“最喜欢”,以便不喜欢的项目出现在不喜欢的项目列表中,而最喜欢的项目出现在最喜欢的项目列表中。我有一个文件 dataContext.tsx 是这样的:

import Data from './data.json'

let rawData: Bot[] = [...Data]
rawData.forEach( item => item.favorite = false )


export function createDataCtx<StateType, ActionType>(
    reducer: Reducer<StateType, ActionType>,
    initialState: StateType
) {
    const defaultDispatch: Dispatch<ActionType> = () => initialState
    const ctx = createContext({
        state: initialState,
        dispatch: defaultDispatch, // just to mock out the dispatch type and make it not optioanl
    })
    function Provider(props: PropsWithChildren<{}>) {
        const [state, dispatch] = useReducer<Reducer<StateType, ActionType>>(reducer, initialState)
        return <ctx.Provider value={{ state, dispatch }} {...props} />
    }
    return [ctx, Provider] as const
}

export const initialState = [...rawData]
type AppState = typeof initialState
type Action = 
    | { type: 'favorite', shortName: string }
    | { type: 'unFavorite', shortName: string }

export function reducer(state: AppState, action: Action): AppState {
    switch(action.shortName){
        case 'favorite':
            console.log('favorite action triggered!!')
            return state.map( (item: Bot) => item.shortName === action.shortName // will have to map the elements with the index when using it so we van pass the index
                ? {...item, favorite: true}
                : item
            )
        case 'unFavorite':
            console.log('unFavorite action triggered!!')
            return state.map( (item: Bot) => item.shortName === action.shortName // will have to map the elements with the index when using it so we van pass the index
                ? {...item, favorite: false}
                : item
            )
        default:
            return state
    }
}

我在应用程序组件中像这样使用我的 Provider:

function App() {
  const [ , DataProvider] = createDataCtx(reducer, initialState)
  return (
    <DataProvider>
      <ThemeProvider theme={Theme}>
        <AppStyles>
          <Router>
            <Header />
            <Content />
          </Router>
        </AppStyles>
      </ThemeProvider>
    </DataProvider>
  );
}

然后我在另一个名为 Cards.tsx 的组件中使用上下文,如下所示:

const [ctx, DataProvider] = createDataCtx(reducer, initialState)
const DataContext = ctx

const Cards = () => {
    
    const {state, dispatch } = useContext(DataContext)
    const faveBotsList = state.filter( item => item.favorite === true)
    const unfaveBotsList = state.filter( item => item.favorite === false )

    return (
        <CardsStyles>
            <CardsRow>
                <FavTitle>Favorites</FavTitle>
            </CardsRow>
            <FavWrap>
                {faveBotsList.map((item) => (
                    <BotCard 
                        key={item.shortName} 
                        favorite={item.favorite} 
                        name={item.name} 
                        shortName={item.shortName} 
                        onStarClick={ () => dispatch({type: 'unFavorite', shortName: item.shortName}) } 
                    />
                ))}
            </FavWrap>
            <CardsWrap>
                {unfaveBotsList.map((item) => (
                    <BotCard 
                        key={item.shortName}
                        favorite={item.favorite}
                        name={item.name}
                        shortName={item.shortName}
                        onStarClick={ () => dispatch({type: 'favorite', shortName: item.shortName}) }/>
                ))}
            </CardsWrap>
        </CardsStyles>
            
    )
}

如果您想查看它,这里是“BotCard”组件代码:

const BotCard = (props: any) => {
    const { favorite, name, shortName, onStarClick } = props
    return (
        <StyledBCard className='col-sm-4 col-md-3 col-lg-2'>
            <Row>
                <FavoriteStar favorite={favorite} className='float-left' onStarClick={onStarClick} />
            </Row>
            <Row className='justify-content-center'>
                <BotImage imageSrc={TestImage} />
            </Row>
            <Row>
                <BotName>{name}</BotName>
            </Row>
            <Row>
                <BotShortName>{shortName}</BotShortName>
            </Row>
        </StyledBCard>
    )
}

'onStarClick' 属性被传递给一个子组件,该子组件将它传递给它的子组件,在那里它被传递给一个样式化组件按钮的 'onClick' 属性。但是点击不会触发调度。我没有看到没有正确实施的内容。

标签: reactjstypescriptdispatch

解决方案


我认为问题在于您在传递调度时正在调用调度。这应该是正确的方法:

<BotCard 
  key={item.shortName}
  favorite={item.favorite}
  name={item.name}
  shortName={item.shortName}
  dispatch={dispatch}
/>

然后,在孩子中调用它:

<button
  onClick={() => dispatch({type: 'favorite', shortName: item.shortName})}
>
  A button
</button>

推荐阅读