我尝试了这个https://medium.com/@markgituma/passing-data-to-props-children-in-react-5399baea0356,但对我不起作用。
/**
* Router.js
*/
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Layout from './components/Layout';
import AddExercise from './pages/AddExercise';
const Router = () => (
<BrowserRouter>
<Layout>
<Switch>
<Route path="/add-exercise" component={AddExercise} />
</Switch>
</Layout>
</BrowserRouter>
);
export default Router;
/**
* Layout.js
*/
class Layout extends React.Component {
render() {
const children = React.Children.map(this.props.children, child => {
return React.cloneElement(child, {
testFunc: () => console.log('test function')
});
});
return (
<div>{ children }</div>
)
}
}
export default Layout;
/**
* AddExercise.js
*/
const AddExercise = ({ testFunc }) => (
<button onClick={testFunc}>Custom Btn</button>
);
export default AddExercise;
当我单击AddExercise.js中的按钮时,没有任何反应。可能是因为我正在尝试将它与react-router-dom一起使用?有解决办法吗?
答案 0 :(得分:0)
您遇到的问题是,当您尝试使用testFunc
将cloneElement
传递给子级时,它作为对Switch Component(在您的情况下是子级或Layout Component)的支持而传递。并且switch组件对此道具没有任何作用,并且不会传递给AddExercise
组件。
处理情况的最佳方法是避免使用cloneElement
并直接在布局组件中使用路线
/**
* Router.js
*/
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Layout from './components/Layout';
import AddExercise from './pages/AddExercise';
const Router = () => (
<BrowserRouter>
<Route component={Layout} /> // This is needed so that Layout gets the Router props
</BrowserRouter>
);
export default Router;
/**
* Layout.js
*/
class Layout extends React.Component {
render() {
return (
<div>
<Switch>
<Route path="/add-exercise" render={(props) => <AddExercise {...props} testFunc: () => console.log('test function')/>} />
</Switch>
</div>
)
}
}
export default Layout;
/**
* AddExercise.js
*/
const AddExercise = ({ testFunc }) => (
<button onClick={testFunc}>Custom Btn</button>
);
export default AddExercise;
其他不涉及在Layout中编写Routes的解决方案将包括创建另一个包含Routes之类的组件
<BrowserRouter>
<Layout>
<ChildRoutes />
</Layout>
</BrowserRouter>
ChildRoutes.js
export const ChildRoutes = ({ testFunc }) => {
<Switch>
<Route path="/add-exercise" render={(props) => <AddExercise {...props} testFunc={testFunc}/>} />
</Switch>
}
答案 1 :(得分:0)
如您共享的link中所述,我们应该将布局组合到一个组件中。您可以尝试创建一个新组件,例如“ FullLayout”,其中同时包含Layout和AddExercise组件。
/**
FullLayout.js
*/
import React from 'react'
import Layout from './Layout'
import AddExercise from '../pages/AddExercise'
class FullLayout extends React.Component {
render = () => {
return (
<Layout>
<AddExercise></AddExercise>
<AddExercise></AddExercise>
</Layout>
);
}
}
export default FullLayout
然后,您只需要在Router.js中将组件修改为FullLayout
<Route path="/add-exercise" component={FullLayout} />
这应该可以解决问题
答案 2 :(得分:0)
谢谢大家!这样做很不错:
<Switch>
<Route path="/add-exercise" render={(props) => <AddExercise {...props} testFunc={testFunc}/>} />
</Switch>
但是看起来有点脏,因为我有多个路线(更多)。因此,我尝试使用Context API,并且非常完美。我不必重组我的组件。
AppContext.js
const AppContext = React.createContext({});
export const AppProvider = AppContext.Provider;
export const AppConsumer = AppContext.Consumer;
Layout.js
import { AppProvider } from './AppContext';
class Layout extends React.Component {
testFunc = () => console.log('test function');
render() {
return (
<AppProvider value={this.testFunc}> // just wrap it with the AppProvider here and send the method
{React.cloneElement(this.props.children, this.props)}
</AppProvider>
)
}
}
AddExercise.js
import {AppConsumer} from './AppContext';
class AddExercise extends React.Component {
render() {
return(
<button onClick={this.props.testFunc}>Custom Btn</button>
);
}
}
export default props => ( // this is the weird part, but works
<AppConsumer>
{context => <AddExercise {...props} testFunc={context} />}
</AppConsumer>
);