天道酬勤,学无止境

反应道具 - 如果另一个道具为空/空,则在道具上设置 isRequired(React props - set isRequired on a prop if another prop is null / empty)

问题

I have a component <Button>.
If the component doesn't has this.props.children, I want to set the prop ariaLabel as isRequired, otherwise in can be optional. How do I do that?

ariaLabel prop not required:

<Button>Add to bag</Button>

ariaLabel prop has to be required:

<Button ariaLabel="Add to bag" icon={ favorite } />

if this.props.children and this.props.ariaLabel are empty, it throws an error saying that this.props.ariaLabel is isRequired

<Button icon={ favorite } />

propTypes:

Button.propTypes = {
    /** icon inside Button. */
    icon: React.PropTypes.object,
    /** Content inside button */
    children: React.PropTypes.node,
    /** Aria-label to screen readers */
    ariaLabel: React.PropTypes.string, /*isRequired if children is empty */
};

Thanks

回答1

您不需要另一个库,'prop-types' 提供了开箱即用的功能。 见 https://facebook.github.io/react/docs/typechecking-with-proptypes.html

例子:

import PropTypes from 'prop-types';

//.......    

ExampleComponent.propTypes = {
    showDelete: PropTypes.bool,
    handleDelete: function(props, propName, componentName) {
        if ((props['showDelete'] == true && (props[propName] == undefined || typeof(props[propName]) != 'function'))) {
            return new Error('Please provide a handleDelete function!');
        }
    },

}
回答2

这可能正是您所需要的:https://github.com/thejameskyle/react-required-if

在您的情况下,您的 propTypes 将是:

import requiredIf from 'react-required-if';

Button.propTypes = {
    /** icon inside Button. */
    icon: React.PropTypes.object,
    /** Content inside button */
    children: React.PropTypes.node,
    /** Aria-label to screen readers */
    ariaLabel: requiredIf(React.PropTypes.string, props => !props.children), /*isRequired if children is empty */
};
回答3

要添加到上面@chickenchilli 的答案,您可以将其抽象为更方便的辅助函数,如下所示:

条件属性类型.js

export default function conditionalPropType(condition, message) {
  if(typeof condition !== 'function') throw "Wrong argument type 'condition' supplied to 'conditionalPropType'";
  return function(props, propName, componentName) {
    if (condition(props, propName, componentName)) {
      return new Error(`Invalid prop '${propName}' '${props[propName]}' supplied to '${componentName}'. ${message}`);
    }
  }
}

我的组件.js

import PropTypes from 'prop-types';
import conditionalPropType from './conditionalPropType';

[...]

MyComponent.propTypes = {
  conditionProp: PropTypes.bool,
  dependentProp: conditionalPropType(props => (props.condition && typeof(props.someProp) !== 'boolean'), "'dependentProp' must be boolean if 'conditionProp' is true"),
};
回答4

使用isRequiredIf

4 年前有一个 PR 将isRequiredIf添加到 PropTypes 库中。 不幸的是,即使在那个时候,他们也将 PropTypes 库置于维护模式并且不会将其合并。

我工作的公司仍然使用 PropTypes,所以我们分叉了 PropTypes 库的master分支并添加了这个功能。

所以现在你可以做这样的事情:

ariaLabel: PropTypes.string.isRequiredIf( props => props.children )

超级干净和最小。

通过使用以下内容更新您的package.json ,随意在您自己的项目中使用我们的 fork:

"prop-types": "github:cntral/prop-types#isRequiredIf"

注意:它不需要布尔参数,只需要传递道具并需要返回布尔值的函数。

回答5

我认为这些解决方案有点矫枉过正,部分原因是问题要求这样做。

我认为您不应该在这种情况下使您的代码复杂化,您应该致力于保持代码干净。 您可以在render上执行此操作而不是在propsTypes上执行此propsTypes

...
render(){
  if(!this.children || !this.ariaLabel) { 
     throw "You need children or ariaLabel"; 
     return;
  }
  //rest of the code.
}

...

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 反应:内联有条件地将prop传递给组件(React: inline conditionally pass prop to component)
    问题 我想知道是否有比使用if语句更好的有条件地传递道具的方法。 例如,现在我有: var parent = React.createClass({ propTypes: { editable: React.PropTypes.bool.isRequired, editableOpts: React.PropTypes.shape({...}) }, render: function() { if(this.props.editable) { return ( <Child editable={this.props.editableOpts} /> ); } else { // In this case, Child will use the editableOpts from its own getDefaultProps() return ( <Child /> ); } } }); 没有if语句,有没有办法写这个? 我正在按照JSX中的一种inif-if语句的思路进行思考: var parent = React.createClass({ propTypes: { editable: React.PropTypes.bool.isRequired, editableOpts: React.PropTypes.shape({...}) }, render: function()
  • React组件中的子项prop(children prop in React component)
    问题 我正在学习此刻的反应。 这是代码的链接-http://redux.js.org/docs/basics/ExampleTodoList.html 我在理解这段代码的内容时遇到了一些困难 const Link = ({ active, children, onClick }) => { if (active) { return <span>{children}</span> } return ( <a href="#" onClick={e => { e.preventDefault() onClick() }} > {children} </a> ) } Link.propTypes = { active: PropTypes.bool.isRequired, children: PropTypes.node.isRequired, onClick: PropTypes.func.isRequired } 我最难以理解此片段 return ( <a href="#" onClick={e => { e.preventDefault() onClick() }} > {children} </a> ) } {children}在这里是什么意思? 它有什么作用? 这是怎么做的? children: PropTypes.node.isRequired, 上一行中的节点是什么意思?
  • 反应生命周期方法的理解(react lifecycle methods understanding)
    问题 我是React.js的新手,我正在努力理解React生命周期方法中的几种方法。 到目前为止,我有一些让我感到困惑的事情: 1) 据我了解, componentWillUpdate和componentWillReceiveProps之间的区别在于,当父项更改道具时将调用componentWillReceiveProps ,我们可以使用setState( componentWillReceiveProps中该孩子的setState)。 例如:react-table-sorter-demo var App = React.createClass({ getInitialState: function() { return {source: {limit: "200", source: "source1"}}; }, handleSourceChange: function(source) { this.setState({source: source}); }, render: function() { return ( <div> <DataSourceSelectors onSourceChange={this.handleSourceChange} source={this.state.source} /> <TableSorter dataSource=
  • 道具验证中缺少反应 eslint 错误(React eslint error missing in props validation)
    问题 我有下一个代码,eslint throw: 反应/道具类型 onClickOut; 道具验证中缺少反应/道具类型的孩子; 道具验证中缺少 propTypes已定义,但 eslint 无法识别它。 import React, { Component, PropTypes } from 'react'; class IxClickOut extends Component { static propTypes = { children: PropTypes.any, onClickOut: PropTypes.func, }; componentDidMount() { document.getElementById('app') .addEventListener('click', this.handleClick); } componentWillUnmount() { document.getElementById('app') .removeEventListener('click', this.handleClick); } handleClick = ({ target }: { target: EventTarget }) => { if (!this.containerRef.contains(target)) { this.props.onClickOut()
  • 如何将没有价值的道具传递给组件(How to pass props without value to component)
    问题 如何将没有价值的道具传递给反应组件? <SomeComponent disableHeight> {/* here */} {({width}) => ( <AnotherComponent autoHeight {/* and here */} width={width} height={300} {...otherProps} /> )} </SomeComponent> 注意 - 没有为这些道具指定默认道具值。 我似乎找不到任何关于它的引用,但是通过观察这些属性的值,它们默认分配为true 。 回答1 您传递的内容被编译器解释为布尔属性。 编写纯 HTML 时也是如此; 没有值的属性被解释为布尔值true 。 由于 JSX 是用于编写 HTML 的语法糖,因此它具有相同的行为是有道理的。 React 官方文档有以下内容: 布尔属性这在使用 HTML 表单元素时经常出现,具有禁用、必需、选中和只读等属性。 省略属性的值会导致 JSX 将其视为 true。 要传递 false,必须使用属性表达式。 //这两个在JSX是等效的用于禁用的按钮<input type="button" disabled />; <input type="button" disabled={true} />; //这两个在 JSX 中等价于不禁用按钮<input type="button" />;
  • ReactJs:this.props.children 的 PropTypes 应该是什么?(ReactJs: What should the PropTypes be for this.props.children?)
    问题 给定一个呈现其子项的简单组件: class ContainerComponent extends Component { static propTypes = { children: PropTypes.object.isRequired, } render() { return ( <div> {this.props.children} </div> ); } } export default ContainerComponent; 问题:children prop的propType应该是什么? 当我将它设置为一个对象时,当我使用具有多个子项的组件时它会失败: <ContainerComponent> <div>1</div> <div>2</div> </ContainerComponent> 警告:失败的道具类型:提供给ContainerComponent array类型的无效道具children项,预期的object 。 如果我将它设置为一个数组,如果我只给它一个孩子,它就会失败,即: <ContainerComponent> <div>1</div> </ContainerComponent> 警告:道具类型失败:提供给 ContainerComponent 的类型对象的道具子项无效,需要数组。 请指教,我是否应该不打扰对子元素进行 propTypes 检查?
  • React 中至少需要一个道具(At least one required prop in React)
    问题 我需要制作至少一种所需的道具: MyComponent.propTypes = { data: PropTypes.object, url: PropTypes.string }; 所以在上面的例子中,必须提供data或url prop。 这里的用例是用户可以提供data或url 。 如果提供了url ,则组件将获取data 。 额外问题:我如何做至少一个道具与只做一个道具? 回答1 PropTypes 实际上可以将自定义函数作为参数,因此您可以执行以下操作: MyComponent.propTypes = { data: (props, propName, componentName) => { if (!props.data && !props.url) { return new Error(`One of props 'data' or 'url' was not specified in '${componentName}'.`); } }, url: (props, propName, componentName) => { if (!props.data && !props.url) { return new Error(`One of props 'url' or 'data' was not specified in '${componentName}'.`)
  • React-如何从查询字符串获取参数值?(React - How to get parameter value from query string?)
    问题 从服务器重定向后,如何在Twitter的单点登录过程生成的URL中在route.jsx文件中定义路由以捕获__firebase_request_key参数值? http://localhost:8000/#/signin?_k=v9ifuf&__firebase_request_key=blablabla 我尝试使用以下路由配置,但:redirectParam没有捕获所提到的参数: <Router> <Route path="/" component={Main}> <Route path="signin" component={SignIn}> <Route path=":redirectParam" component={TwitterSsoButton} /> </Route> </Route> </Router> 回答1 通用的React Router v4和React Router v5 React Router v4不再为您解析查询,但是您只能通过this.props.location.search (或useLocation,请参见下文)进行访问。 出于某些原因,请参阅nbeuchat的答案。 例如,将qs库导入为qs即可 qs.parse(this.props.location.search, { ignoreQueryPrefix: true })._
  • 如何在 React 组件上设置组件默认道具(How to set component default props on React component)
    问题 我使用下面的代码在 React 组件上设置默认道具,但它不起作用。 在render()方法中,我可以看到输出“undefined props”被打印在浏览器控制台上。 如何为组件 props 定义默认值? export default class AddAddressComponent extends Component { render() { let {provinceList,cityList} = this.props if(cityList === undefined || provinceList === undefined){ console.log('undefined props') } ... } AddAddressComponent.contextTypes = { router: React.PropTypes.object.isRequired } AddAddressComponent.defaultProps = { cityList: [], provinceList: [], } AddAddressComponent.propTypes = { userInfo: React.PropTypes.object, cityList: PropTypes.array.isRequired, provinceList: PropTypes
  • React中的state和props有什么区别?(What is the difference between state and props in React?)
    问题 我正在观看有关React的Pluralsight课程,并且讲师说不应更改道具。 我现在正在阅读有关道具与状态的文章(uberVU / react-guide),它说 道具和状态更改都会触发渲染更新。 在文章的后面,它说: 道具(属性的缩写)是组件的配置,如果可以的话,它是选项。 他们是从天上来的,是一成不变的。 所以道具可以改变,但它们应该是不变的? 什么时候应该使用道具,什么时候应该使用状态? 如果您有React组件需要的数据,是否应该通过getInitialState通过getInitialState或在React组件中进行设置来传递数据? 回答1 道具和状态是相关的。 一个组件的状态通常会成为子组件的道具。 道具作为React.createElement()的第二个参数传递给父对象的render方法中的子对象,或者,如果您使用的是JSX,则将其作为更熟悉的标签属性。 <MyChild name={this.state.childsName} /> 父级的childsName状态值成为子级的this.props.name 。 从孩子的角度来看,prop这个名字是一成不变的。 如果需要更改,则父级只需更改其内部状态即可: this.setState({ childsName: 'New name' }); React会为您将它传播给孩子。 接natural而来的自然问题是
  • 反应:检查器不是一个函数(React: checker is not a function)
    问题 我在 React 应用程序的控制台中收到了这条奇怪的警告消息。 警告:失败的 propType:检查器不是函数 检查Chart的渲染方法。 我根本没有任何检查方法。 如果我删除我的propTypes ,警告就会消失。 有任何想法吗? 我的反应组件: var Chart = React.createClass({ //... propTypes: { legend: React.PropTypes.bool, max: React.PropTypes.number, min: React.PropTypes.number, series: React.PropTypes.arrayOf( React.PropTypes.shape({ label: React.PropTypes.string, values: React.PropTypes.arrayOf( React.PropTypes.arrayOf( React.PropTypes.oneOfType( React.PropTypes.number, React.PropTypes.object // Date ) ) ), colorIndex: React.PropTypes.string }) ).isRequired, threshold: React.PropTypes.number, type: React
  • 如何有条件地向React组件添加属性?(How do I conditionally add attributes to React components?)
    问题 如果满足特定条件,是否有办法仅将属性添加到R​​eact组件? 我应该在渲染后基于Ajax调用将required和readOnly属性添加到表单元素中,但是由于readOnly =“ false”与完全省略该属性不同,因此我看不到如何解决此问题。 下面的示例应该解释我想要的内容,但是它不起作用(解析错误:意外的标识符)。 var React = require('React'); var MyOwnInput = React.createClass({ render: function () { return ( <div> <input type="text" onChange={this.changeValue} value={this.getValue()} name={this.props.name}/> </div> ); } }); module.exports = React.createClass({ getInitialState: function () { return { isRequired: false } }, componentDidMount: function () { this.setState({ isRequired: true }); }, render: function () { var isRequired = this
  • ReactJS应用程序-弹性VS快速失败(ReactJS Application - resiliency VS failing fast)
    问题 我正在开发React应用程序,这是我用于组件的方法:我使用PropTypes验证来验证希望收到的道具,但是我仍然分配默认值以避免它被使用如果接收到的数据出现问题,则中断。 最近,有人告诉我,我们不应该这样做,因为道具是我们期望父母提供的,并且如果不遵守合同规定的话,则可能会破坏组件。 哪种方法正确,利弊何在? 我的一些考虑值得深思。 按照我最初的方法,在测试中,我显式测试传递给被测组件的默认值,这些默认值会传递一些无效数据,并期望仍然打印出有效快照。 测试不会由于某些不良数据而失败,但是我会打印出PropTypes验证警告(如果需要,我可以将其转换为错误-我想-或在测试中将其模拟出来时保持沉默)。 在测试和实际应用程序中,这些警告都更加简洁明了,而不是仅仅看到一个错误消息,即“无法从未定义中读取'someProp'”或类似错误(并使React渲染周期中断)。 propType验证直接并清楚地告诉您您做错了什么(您以错误的类型传递了prop,prop完全丢失,等等)。 相反,使用第二种方法会因为应用程序中断而导致测试失败。 我认为,只有在测试覆盖率非常好(90/100%)的情况下,这才是一个好方法,否则会带来风险-它可能会上线并在极端情况下中断,从而破坏产品声誉。 重构或需求变更经常发生,并且某些极端情况最终可能会导致不希望有的数据中断应用程序,并且无法在自动或手动测试中捕获。
  • 使用React Router V4以编程方式导航(Programmatically navigate using react router V4)
    问题 我刚刚从v3到v4替换了react-router 。 但是我不确定如何以编程方式导航Component的成员函数。 即在handleClick()函数中,我想在处理一些数据后导航到/path/some/where 。 我曾经通过以下方式做到这一点: import { browserHistory } from 'react-router' browserHistory.push('/path/some/where') 但是我在v4中找不到这样的接口。 如何使用v4导航? 回答1 如果您以浏览器环境为目标,则需要使用react-router-dom软件包,而不是react-router 。 它们遵循与React相同的方法,以分离核心( react )和平台特定的代码( react-dom , react-native ),其细微差别在于您无需安装两个单独的软件包,因此环境包包含您需要的一切。 您可以通过以下方式将其添加到您的项目中: yarn add react-router-dom 或者 npm i react-router-dom 您需要做的第一件事是提供<BrowserRouter>作为应用程序中最顶层的父组件。 <BrowserRouter>使用HTML5 history API并为您管理它,因此您不必担心自己进行实例化并将其作为道具传递给<BrowserRouter
  • 强制反应路由器加载页面,即使我们已经在该页面上(Forcing a React-Router <Link> to load a page, even if we're already on that page)
    问题 有没有办法强制 React-Router <Link>从路径加载页面,即使当前位置已经是该页面? 我似乎在 react-router 文档中找不到任何提及。 我们在“申请”路线上有一个页面,用于加载带有英雄图像、一些解释性文本等的登录页面,以及一个“申请此计划”按钮,用于交换充当申请表的内容。 这一切都发生在同一个“申请”路线上,因为用户不应该首先点击登录页面就不能直接导航到这个表单。 然而,当他们打开这个表单,并再次点击导航菜单中的应用链接时,整个页面应该像第一次装载一样重新加载,让它们再次“返回”(但实际上,向前)到登录页面. 相反,单击<Link>什么也不做,因为 react-router 看到我们已经在“应用”页面上,因此不会卸载当前页面然后挂载另一个页面。 有没有办法强制它在安装请求的页面之前卸载当前页面,即使它是用户应该已经在的页面? (例如通过<Link>属性?) 回答1 我用来解决我对此的小需求的一个修复是更改 React-Router 查看的位置。 如果它看到我们已经在的位置(如您的示例中所示)它不会做任何事情,但是通过使用位置对象并更改它,而不是使用纯字符串路径,React-Router 将“导航”到新位置,即使路径看起来相同。 您可以通过设置一个做到这一点key这是从当前密钥不同的(类似于如何反应的渲染依赖于key )与state属性
  • 使用React路由器以编程方式导航(Programmatically navigate using React router)
    问题 通过react-router我可以使用Link元素来创建由react路由器本地处理的链接。 我在内部看到它调用this.context.transitionTo(...) 。 我想导航。 不是来自链接,而是来自下拉菜单(例如)。 如何在代码中执行此操作? 这是什么this.context ? 我看到了Navigation mixin,但是没有mixins可以做到吗? 回答1 带有钩子的React Router v5.1.0 如果您使用React> 16.8.0和功能组件,则在React Router> 5.1.0中有一个新的useHistory钩子。 import { useHistory } from "react-router-dom"; function HomeButton() { const history = useHistory(); function handleClick() { history.push("/home"); } return ( <button type="button" onClick={handleClick}> Go home </button> ); } 反应路由器v4 使用React Router v4,您可以采用三种方法在组件内进行编程路由。 使用withRouter高阶组件。 使用合成并渲染<Route> 使用context
  • React - 通过传递道具更改输入默认值(React - change input defaultValue by passing props)
    问题 考虑这个例子: var Field = React.createClass({ render: function () { // never renders new value... return ( <div> <input type="text" defaultValue={this.props.value || ''} /> </div> ); } }); var App = React.createClass({ getInitialState: function () { return {value: 'Hello!'}; }, changeTo: function (str) { this.setState({value: str}); }, render: function () { return ( <div> <Field value={this.state.value} /> <button onClick={this.changeTo.bind(null, 'Whyyyy?')}>Change to "Whyyyy?"</button> <button onClick={this.changeTo.bind(null, void 0)}>Change to undefined</button> </div> ); } }); React.render(
  • 反应/助焊剂和XHR /路由/缓存(React/Flux and xhr/routing/caching)
    问题 这更像是“您对此有何看法/我对此是否正确?” 问题。 在理解Flux的过程中尝试尽可能严格,我试图弄清楚在何处进行XHR调用,处理Websockets /外部刺激,进行路由等。 通过阅读各种文章,访谈和查看Facebook实例,我发现了几种处理这些问题的方法。 严格遵循通量,动作创建者是执行所有XHR调用的人,并有可能在请求完成前后触发“ PENDING/SUCCESS/FAILURE动作。 另一个是,来自Facebook的Ian Obermiller,所有READ(GETs)请求均由商店直接处理(无需Action创建者/调度员的参与),而WRITE(POSTs)请求则由Action Creators处理整个action>dispatcher>store流。 我们得出/希望坚持的一些理解/结论: 理想情况下,任何进出系统的事情都只能通过操作来进行。 离开/进入系统的异步呼叫将具有PENDING/PROGRESS(think file uploads)/SUCCESS/FAILURE操作。 整个应用程序中的单个调度程序。 Action>Dispatcher>Store调用严格同步,以遵守调度程序,而无法在内部启动另一个调度程序以避免链接事件/操作。 存储在视图之间持久化(考虑到它的单页应用程序,您希望能够重用数据) 我们得出了一些结论,但我并不完全满意:
  • 组件应在什么嵌套级别从Flux商店读取实体?(At what nesting level should components read entities from Stores in Flux?)
    问题 我正在重写我的应用程序以使用Flux,但从商店检索数据时遇到问题。 我有很多组件,它们嵌套很多。 其中一些很大( Article ),一些又小又简单( UserAvatar , UserLink )。 我一直在努力在组件层次结构中的什么地方应该从商店读取数据。 我尝试了两种极端的方法,但我都不喜欢: 所有实体组件都读取自己的数据 需要从Store获得一些数据的每个组件仅接收实体ID,并自行检索实体。 例如, Article传递了articleId , UserAvatar和UserLink传递了userId 。 这种方法有几个重大缺点(在代码示例下讨论)。 var Article = React.createClass({ mixins: [createStoreMixin(ArticleStore)], propTypes: { articleId: PropTypes.number.isRequired }, getStateFromStores() { return { article: ArticleStore.get(this.props.articleId); } }, render() { var article = this.state.article, userId = article.userId; return ( <div> <UserLink
  • 如何从浏览器设置 React 组件状态和道具(How to set React component state and props from browser)
    问题 是否有可能通过浏览器(从另一个脚本内部或通过控制台)访问和设置现有 React 组件的状态和道具? 我知道 Angular 有一种方法可以访问范围和更改变量,但是使用 React 我一直找不到方法。 我认为一定有某种方式,因为 Facebook 的 React Developer Tools 扩展能够从页面上的 React 组件获取所有信息(道具、状态、组件、事件侦听器),并有可能更改它们。 如果有可能通过 JavaScript 做到这一点,那将是怎样的方式呢? 回答1 如果你有 React devtools 扩展,你可以通过你的浏览器控制台使用$r访问 React 范围。 首先,在 React devtools 选项卡中选择您想要操作的组件: 然后,使用$r对组件进行操作,例如使用$r.state读取状态或使用$r.setState({ ... })设置状态: 回答2 要从浏览器设置反应组件的状态,您可以将一个函数绑定到将触发设置状态的窗口对象。 在 react 组件的构造函数中,您可以这样做。 constructor (props){ super(props); window.changeComponentState = (stateObject) => { this.setState ({stateObject}); } } 在浏览器控制台中,您可以执行此操作。