ReactJS:如何用新Context API扩展属性为多组件传相同Props
优化React Context传参的几种方案
嘿,刚接触React Context确实会碰到这种重复写props的麻烦,我来给你几个优化方案,让代码清爽起来!
先还原一下你的原始代码场景(方便对照):
<ResultsProvider> <ResultsContext.Consumer> {(val) => ( <Switch> <Route exact path={'/'} render={ (props) => <Today results={val.results} loading={val.loading} view={val.view} /> } /> <Route path={'/all'} render={ (props) => <All results={val.results} loading={val.loading} view={val.view} /> } /> </Switch> )} </ResultsContext.Consumer> </ResultsProvider>
方案1:用扩展运算符直接展开Context值
这是最直接的优化,不用手动逐个列出props,直接用...val把Context里的所有属性展开传给组件:
<ResultsProvider> <ResultsContext.Consumer> {(val) => ( <Switch> {/* 把Context值和Route自带的props一起展开 */} <Route exact path={'/'} render={ (props) => <Today {...val} {...props} /> } /> <Route path={'/all'} render={ (props) => <All {...val} {...props} /> } /> </Switch> )} </ResultsContext.Consumer> </ResultsProvider>
解释:...val会自动把val里的results、loading、view等属性全部作为props传给组件,省掉了重复写的麻烦。如果你的组件需要用到Route提供的match、location等props,就加上...props一起展开。
方案2:用useContext Hook(函数组件首选)
如果<Today>和<All>是函数组件,那完全可以抛弃Consumer嵌套,用React提供的useContext Hook直接获取Context值,代码会简洁很多:
首先在组件内部使用useContext:
import { useContext } from 'react'; import ResultsContext from './ResultsContext'; function Today(props) { // 直接获取Context里的所有值,也可以按需解构 const { results, loading, view } = useContext(ResultsContext); // 接下来直接用这些值写组件逻辑就行 return ( <div> {loading ? <p>加载中...</p> : <ul>{results.map(item => <li key={item.id}>{item.content}</li>)}</ul>} </div> ); } function All(props) { const { results, loading, view } = useContext(ResultsContext); return ( // 你的组件内容 ); }
然后路由部分可以简化到极致:
<ResultsProvider> <Switch> <Route exact path={'/'} component={Today} /> <Route path={'/all'} component={All} /> </Switch> </ResultsProvider>
这种方式完全消除了Consumer的嵌套层级,代码可读性提升不少,也是React官方推荐的函数组件写法。
方案3:封装高阶组件(HOC,适合类组件)
如果你的组件是类组件,或者想统一给多个组件注入Context值,可以封装一个高阶组件(HOC):
import ResultsContext from './ResultsContext'; // 定义一个HOC,接收目标组件,返回注入了Context值的新组件 function withResults(Component) { return function WrappedComponent(props) { return ( <ResultsContext.Consumer> {(val) => <Component {...val} {...props} />} </ResultsContext.Consumer> ); }; }
然后给你的组件包裹这个HOC:
// 假设Today和All是类组件 class Today extends React.Component { // 组件逻辑 } class All extends React.Component { // 组件逻辑 } // 用HOC包裹,注入Context值 const TodayWithResults = withResults(Today); const AllWithResults = withResults(All);
最后路由里直接使用包裹后的组件:
<ResultsProvider> <Switch> <Route exact path={'/'} component={TodayWithResults} /> <Route path={'/all'} component={AllWithResults} /> </Switch> </ResultsProvider>
这样以后任何需要用到这些Context值的组件,只要用withResults包裹就行,不用重复写Consumer的逻辑。
内容的提问来源于stack exchange,提问作者Nar
相关产品推荐
相关产品推荐

