将道具传递给克隆的子元素,给出未知道具警告

Passing props to a cloned child element giving Unknown Prop warning

我在 React 中有一个 AdminLayout,它依次以这种方式加载子元素:

class AdminLayout extends Component {

  constructor(props){
    super(props)
    this.state = {
      flash: { msg: "some message", type: undefined}
    }
  }

  updateFlash(flash){
    this.state.flash = flash
  }

  render() {
    return(
      <div>
        <FlashMessage flash={this.state.flash} />
        <NavBar/>
        { React.cloneElement(this.props.children, {updateFlash: this.updateFlash})}
      </div>
    )
  }
}

这里的想法是我打算让我的子元素更新 AdminLayout 中的闪存状态。但是,使用代码 {updateFlash: this.updateFlash} 我收到以下错误:

Warning: Unknown prop `updateFlash` on <div> tag. Remove this prop from the element. For details, see https://facebook.github.io/react/warnings/unknown-prop.html
    in div (created by Grid)
    in Grid (created by LocationEdit)

我查看了文档,我不认为我正在处理任何案例。我也没有尝试直接在任何 div 上设置道具。

有人以前见过这样的东西吗?

Hrm...了解我的内部组件是什么样子也可能有所帮助。我试图过滤掉任何不必要的东西......:[=​​14=]

import React, {Component} from 'react'
import AdminLayout from '../components/layouts/AdminLayout'
import LocationsSource from '../sources/LocationsSource'
import {Button, Grid, Row, Col, FormGroup, FormControl, ControlLabel, HelpBlock} from 'react-bootstrap'
import { browserHistory } from 'react-router'

class LocationEdit extends Component {

  constructor(props) {
    super(props)
    this.handleSubmit = this.handleSubmit.bind(this)

    this.state = {
      loading: true,
      location: {
        name: "",
        site_link: "",
        description: ""
      }
    }
  }

  handleSubmit = (event) => {
    event.preventDefault()

    let data = this.state.location

    if(data._id != undefined) {
      LocationsSource.update(data).then((response) => {
        browserHistory.push('/admin/locations/');
      })
    } else {
      LocationsSource.create(data).then((response) => {
        browserHistory.push('/admin/locations/');
      })
    }
  }

  componentDidMount() {
    if(this.props.params.id)
      LocationsSource.find(this.props.params.id).then((result) => {
        this.setState({loading: false, location: result})
      })
    else{
      this.setState({loading: false, location: {}})
    }
  }

  handleChange = (event) => {
    let change = {location: this.state.location}
    change['location'][event.target.name] = event.target.value
    this.setState(change)
  }

  componentWillUnmount() {}

  render() {
    let location = this.state.location

    if(this.state.loading)
      return(
        <AdminLayout>
          <Row>
            <img src="/assets/images/loading.gif" />
          </Row>
        </AdminLayout>
      )
    else
      return(
        <AdminLayout>
          <Grid>
            <Row>
              <Col xs={8} md={8}>
                <h2>Location</h2>
              </Col>
            </Row>
            <Row>
              <Col xs={8} md={8}>
                <form onSubmit={this.handleSubmit}>
                  <FormGroup controlId={"name"}>
                    <ControlLabel>Name:</ControlLabel>
                    <FormControl onChange={this.handleChange} name="name" type="text" defaultValue={location.name} />
                  </FormGroup>
                  <Button type="submit">
                    Submit
                  </Button>
                </form>
              </Col>
            </Row>
          </Grid>
        </AdminLayout>
      )

  }
}

export default LocationEdit
  updateFlash(flash){
    this.setState({ flash });
  }

  render() {
    return(
      <div>
        <FlashMessage flash={this.state.flash} />
        <NavBar/>
        { React.cloneElement(this.props.children, {updateFlash: this.updateFlash.bind(this)})}
      </div>
    )
  }

好的,问题的根源最终是我使用 react-router 不正确。在我添加问题的最后一部分之前,这是不可能看到的,它表明我正在从 sub-component LocationEdit.

渲染 AdminLayout

我这样做是因为 react-router 我直接加载该页面,我没有意识到我实际上需要先加载布局,并且需要将子页面定义为子标签。下面是我原来的路线和我做的改动:

render((
  <Router history={browserHistory}>
    <Route path="/admin/" component={Locations} />
    <Route path="locations" component={LocationEdit} />
  </Router>
), document.getElementById('app'));

更改:

render((
  <Router history={browserHistory}>
    <Route path="/admin/" component={AdminLayout} >
      <Route path="locations" component={LocationEdit} />
    </Route>
  </Router>
), document.getElementById('app'));

然后我从 LocationEdit 页面中取出了 AdminLayout 标签。我有一种感觉,它试图将 props 直接加载到 <Grid> 标记上,而不是像我想象的那样加载到实际组件上。