为什么我使用反应路由器和嵌套组件

时间:2017-03-24 04:17:02

标签: reactjs react-router react-redux react-proptypes

所以,我有一个带反应路由器的站点,还有redux(下面的例子非常简化)

<Route path="/" component={ A } >
  <Route path="/B" component={B} />
</Route>

A.jsx

class A extends Component {
    render () {
        const calculated_value_to_pass_down = FooBar()
        return (
            <div>
                {React.Children.map(this.props.children,
                    (child) => React.cloneElement(child, {
                        required_prop: calculated_value_to_pass_down
                    })
                )}
            </div>
        )
    }
}    
export default A

B.jsx

class B extends Component {
    render () {
        return (
            <div>
                { this.props.required_prop }
            </div>
        )
    }
}    
B.propTypes = {
    required_prop: PropTypes.any.isRequired
}    
export default B

但是,当我转到localhost:8080/B时,我收到错误回溯:

Warning: Failed prop type: The prop `required_prop` is marked as required in `B`, but its value is `undefined`.
in A (created by RouterContext)
in RouterContext (created by Router)
in Router
in Provider

页面100%有效。并且错误在生产中没有发生,但我讨厌出现的错误。

页面实际上从未使用未定义的道具实际呈现,我甚至在调用render之前得到错误。

我知道我可以简单地删除.isRequired并且它会起作用,但这个想法闻起来很烂。

谢谢!

3 个答案:

答案 0 :(得分:1)

我尝试了很多方法,但没有得到这个警告的原因。我可以猜到但不确定的一件事,cloneElement按照DOC

  

克隆并使用element作为起始返回一个新的React元素   点。结果元素将具有原始元素的道具   与新道具合并浅。新的孩子将取代   现有的孩子。

cloneElement复制现有元素,可能是该组件首先被创建而没有道具然后被复制。

临时解决方案是,您可以使用defaultProps来定义prop的默认值,通过执行此操作,它不会抛出警告,如下所示:

B.defaultProps = {
    required_prop: ''
}

答案 1 :(得分:0)

它不会出现在生产中,因为这些警告未在生产中显示/使用,但仍然存在错误。 (propTypes从生产代码中删除)

你的问题是A.jsx甚至在FooBar()完成之前渲染B.jsx,这意味着它发送的calculate_value_to_pass_down的值最初是未定义的,如果你的B.jsx组件不想拥有空道​​具那么解决方法是检查A.jsx中是否compute_value_to_pass_down未定义,如果未定义则不会渲染B.jsx组件。

<div>
   {calculated_value_to_pass_down!==undefined? React.Children.map(this.props.children,
     (child) => React.cloneElement(child, {
        required_prop: calculated_value_to_pass_down
        })
     ) : <div>LOADING</div>}
</div>

答案 2 :(得分:0)

感谢@ malayank-shukla的回答,我意识到问题出在代码的React.cloneElement部分。

还有更多讨论:ReactTraining's Github Issues

似乎解决方案是:

  1. 从PropTypes
  2. 中删除.isRequired
  3. 从PropTypes
  4. 设置默认值
  5. 在包装器组件中包装子组件,使用默认设置道具,直到发送适当的道具(如果您使用B.jsx多个位置并且不想在任何地方删除PropType用法
  6. React-Router v4有一个选项,允许您在路由上编写渲染属性而不是组件属性;但它对我的情况不起作用;或者我不理解它?

    <Route
        exact
        path="/b"
        render={routeProps => <B {...props} {...routeProps} />}
    />
    
  7. 我期待任何其他答案