Вызовите родительский метод с React.cloneElement - PullRequest
0 голосов
/ 06 ноября 2018

Я попробовал это 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, ничего не происходило. Может быть потому, что я пытаюсь использовать его с реактивом-маршрутизатором-домом? Есть какое-нибудь решение?

Ответы [ 3 ]

0 голосов
/ 06 ноября 2018

Мы должны объединить макеты в один компонент, как указано в ссылке , которой вы поделились. Вы можете попробовать создать новый компонент, например, «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

Тогда вам просто нужно изменить компонент на FullLayout в Router.js

<Route path="/add-exercise" component={FullLayout} />

Это должно решить проблему

0 голосов
/ 07 ноября 2018

Спасибо всем! Хорошо работает, делая это:

<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>
);
0 голосов
/ 06 ноября 2018

Проблема в вашем случае заключается в том, что, когда вы пытаетесь передать testFunc дочерним элементам, использующим cloneElement, он передается в качестве опоры для компонента переключения, который в вашем случае является дочерним или компонентом макета. И компонент switch ничего не делает с этим пропом, и он не передается компоненту AddExercise.

Лучший способ справиться с вашим делом - избегать cloneElement и использовать The Route непосредственно в Компоненте Layout

/**
*  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;

Другое решение, которое не включает в себя написание маршрутов в макете, будет включать создание другого компонента, который содержит маршруты, такие как

  <BrowserRouter>
        <Layout>
            <ChildRoutes />
        </Layout>
    </BrowserRouter>

ChildRoutes.js

export const ChildRoutes = ({ testFunc }) => {
    <Switch>
      <Route path="/add-exercise" render={(props) => <AddExercise {...props}  testFunc={testFunc}/>} />
    </Switch>
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...