Jak przekazać komponent reagujący na inny komponent reagujący, aby przetłumaczyć zawartość pierwszego komponentu?

215

Czy istnieje sposób na przekazanie jednego składnika do drugiego reagującego składnika? Chcę utworzyć model reagujący komponent i przekazać inny komponent reagujący, aby przetłumaczyć tę treść.

Edycja: Oto codepen reagJS ilustrujący to, co próbuję zrobić. http://codepen.io/aallbrig/pen/bEhjo

HTML

<div id="my-component">
    <p>Hi!</p>
</div>

ReactJS

/**@jsx React.DOM*/

var BasicTransclusion = React.createClass({
  render: function() {
    // Below 'Added title' should be the child content of <p>Hi!</p>
    return (
      <div>
        <p> Added title </p>
        {this.props.children}
      </div>
    )
  }
});

React.renderComponent(BasicTransclusion(), document.getElementById('my-component'));
Andrew Allbright
źródło

Odpowiedzi:

197

Możesz użyć this.props.childrendo renderowania wszystkich elementów podrzędnych, które zawiera:

const Wrap = ({ children }) => <div>{children}</div>

export default () => <Wrap><h1>Hello word</h1></Wrap>
David Hellsing
źródło
4
Użyłbym tej odpowiedzi. this.props.childrenjest częścią interfejsu API i oczekuje się, że będzie używany w ten sposób. Przykłady zespołu React wykorzystują tę technikę, na przykład podczas przenoszenia rekwizytów i mówienia o jednym dziecku .
Ross Allen,
Z mojego komentarza poniżej: Przekazując go jako rekwizyt, możesz nawet nadać mu nazwę i użyć propTypes, aby wpisać check.
returneax
1
@AndrewAllbright: Twój przykład nie przekazał żadnych dzieci. Działa to: codepen.io/ssorallen/pen/Dyjmk
Ross Allen
A jeśli chcesz następnie uzyskać węzły DOM dzieci: stackoverflow.com/questions/29568721/...
ericsoco
124

Uwaga I pod warunkiem odpowiedzi bardziej szczegółowe tutaj

Opakowanie środowiska wykonawczego:

To najbardziej idiomatyczny sposób.

const Wrapper = ({children}) => (
  <div>
    <div>header</div>
    <div>{children}</div>
    <div>footer</div>
  </div>
);

const App = () => <div>Hello</div>;

const WrappedApp = () => (
  <Wrapper>
    <App/>
  </Wrapper>
);

Zauważ, że childrenjest to „specjalna rekwizyt” w React, a powyższy przykład to cukier składniowy i jest (prawie) równoważny z<Wrapper children={<App/>}/>


Opakowanie inicjujące / HOC

Możesz użyć komponentu wyższego rzędu (HOC). Zostały ostatnio dodane do oficjalnego dokumentu .

// Signature may look fancy but it's just 
// a function that takes a component and returns a new component
const wrapHOC = (WrappedComponent) => (props) => (
  <div>
    <div>header</div>
    <div><WrappedComponent {...props}/></div>
    <div>footer</div>
  </div>
)

const App = () => <div>Hello</div>;

const WrappedApp = wrapHOC(App);

Może to prowadzić do (niewielkiej) lepszej wydajności, ponieważ komponent otoki może zwierać renderowanie o krok do przodu za pomocą funkcji shouldComponentUpdate, podczas gdy w przypadku otoki środowiska wykonawczego rekwizyt podrzędny prawdopodobnie będzie zawsze innym ReactElement i spowoduje ponowne renderowanie nawet jeśli twoje komponenty rozszerzają PureComponent.

Zauważ, że connectRedux był opakowaniem środowiska wykonawczego, ale został zmieniony na HOC, ponieważ pozwala uniknąć niepotrzebnych ponownych renderowań, jeśli użyjesz tej pureopcji (domyślnie jest to prawda)

Nigdy nie powinieneś wywoływać HOC podczas fazy renderowania, ponieważ tworzenie komponentów React może być kosztowne. Powinieneś raczej wywoływać te opakowania podczas inicjalizacji.


Należy zauważyć, że podczas korzystania z funkcjonalnych komponentów, takich jak powyżej, wersja HOC nie zapewnia żadnej użytecznej optymalizacji, ponieważ bezstanowe funkcjonalne komponenty nie są implementowane shouldComponentUpdate

Więcej wyjaśnień tutaj: https://stackoverflow.com/a/31564812/82609

Sebastien Lorber
źródło
29
const ParentComponent = (props) => {
  return(
    {props.childComponent}
    //...additional JSX...
  )
}

//import component
import MyComponent from //...where ever

//place in var
const myComponent = <MyComponent />

//pass as prop
<ParentComponent childComponent={myComponent} />
Joseph Barnes
źródło
Byłoby to prawidłowe, gdyby to było ... React 15.x uniemożliwia zwrócenie komponentu zawierającego wiele węzłów. React 16 (aka React Fibre) pozwoli na wiele węzłów. Oto poprawka dla Twojego kodu przykładowego: const ParentComponent = (props) => ({props.childComponent}); zaimportuj MyComponent z //...where ever const myComponent = <MyComponent /> // przekaż jako prop <ParentComponent childComponent = {myComponent} />
Andrew Allbright
13

Facebook zaleca użycie komponentu bezstanowego Źródło: https://facebook.github.io/react/docs/reusable-components.html

W idealnym świecie większość twoich komponentów byłaby funkcjami bezstanowymi, ponieważ w przyszłości będziemy mogli również dokonywać optymalizacji wydajności specyficznych dla tych komponentów, unikając niepotrzebnych kontroli i alokacji pamięci. Jest to zalecany wzór, jeśli to możliwe.

function Label(props){
    return <span>{props.label}</span>;
}

function Hello(props){
    return <div>{props.label}{props.name}</div>;
}

var hello = Hello({name:"Joe", label:Label({label:"I am "})});

ReactDOM.render(hello,mountNode);
Sud
źródło
13

Możesz przekazać to jako normalną rekwizyt: foo={<ComponentOne />}

Na przykład:

const ComponentOne = () => <div>Hello world!</div>
const ComponentTwo = () => (
  <div>
    <div>Hola el mundo!</div>
    <ComponentThree foo={<ComponentOne />} />
  </div>
)
const ComponentThree = ({ foo }) => <div>{foo}</div>
Fellow Stranger
źródło
9

Wolę używać wbudowanego interfejsu API React:

import React, {cloneElement, Component} from "react";
import PropTypes from "prop-types";

export class Test extends Component {
  render() {
    const {children, wrapper} = this.props;
    return (
      cloneElement(wrapper, {
        ...wrapper.props,
        children
      })
    );
  }
}

Test.propTypes = {
  wrapper: PropTypes.element,
  // ... other props
};

Test.defaultProps = {
  wrapper: <div/>,
  // ... other props
};

następnie możesz zastąpić div otoki co chcesz:

<Test wrapper={<span className="LOL"/>}>
  <div>child1</div>
  <div>child2</div>
</Test> 
Fareed Alnamrouti
źródło
5

Możesz przekazać komponent przez. rekwizyty i renderuj je z interpolacją.

var DivWrapper = React.createClass({
    render: function() {
        return <div>{ this.props.child }</div>;
    }
});

Następnie przekażesz propwywołanie child, które będzie składnikiem React.

returneax
źródło
1
Doprowadziłoby to do przekazywania komponentów poprzez atrybuty, a nie jako dzieci. Jeśli użyjesz this.props.childrenzgodnie z sugestią zawartą w innej odpowiedzi, możesz napisać dzieci jako dzieci zamiast attrs.
Ross Allen,
1
@ssorallen nie powiedziałeś, dlaczego ktoś jest lepszy w jakikolwiek sposób ... Przekazując go jako rekwizyt, możesz nawet nadać mu nazwę i użyć propTypes do wpisania tekstu
returneax
1
Każdy element używany w JSX jest tylko składnikiem. Gdyby zastosowali to podejście, nie byłbyś w stanie napisać nawet krótkiego przykładu. To się stanie <div child={this.props.child />.
Ross Allen
1
Sprawdź wersję JavaScript (w co JSX ją zamienia): jsfiddle.net/ssorallen/kvrxcqv8/2 . React.DOM.div, podobnie jak wszystkie podstawowe komponenty, korzysta z childrentablicy. Zobacz, jak jest używany w twoim Hellokomponencie, korzysta już z wielu dzieci.
Ross Allen
20
Minusem kontynuowania dyskusji na czacie jest to, że nie są one archiwizowane dla przyszłych czytelników.
ultrafez
3

Późno do gry, ale tutaj jest potężny wzorzec HOC do przesłonięcia elementu przez zapewnienie go jako rekwizytu. To proste i eleganckie.

Załóżmy, że MyComponentrenderuje element fikcyjny A, ale chcesz zezwolić na niestandardowe zastąpienie A, w tym przykładzie B, które otacza Aa, <div>...</div>a także dołącza „!” do propa tekstu:

import A from 'fictional-tooltip';

const MyComponent = props => (
  <props.A text="World">Hello</props.A>
);
MyComponent.defaultProps = { A };

const B = props => (
  <div><A {...props} text={props.text + '!'}></div>
);

ReactDOM.render(<MyComponent A={B}/>);
joneit
źródło
1

W rzeczywistości Twoim pytaniem jest, jak napisać komponent wyższego rzędu (HOC). Głównym celem korzystania z HOC jest zapobieganie wklejaniu kopii. Możesz napisać swój HOC jako czysto funkcjonalny komponent lub jako klasę. Oto przykład:

    class Child extends Component {
    render() {
        return (
            <div>
                Child
            </div>
        );
    }
}

Jeśli chcesz napisać komponent nadrzędny jako komponent oparty na klasach:

    class Parent extends Component {
    render() {
        return (
            <div>
                {this.props.children}
            </div>
        );
    }
}

Jeśli chcesz napisać swojego rodzica jako komponent funkcjonalny:

    const Parent=props=>{
    return(
        <div>
            {props.children}
        </div>
    )
}
Meisam Nazari
źródło
0

Oto przykład nadrzędnego komponentu List reaguj, a rekwizyty zawierają element reagujący. W tym przypadku przekazywany jest tylko jeden składnik reagujący Link (jak widać w renderowaniu dom).

class Link extends React.Component {
  constructor(props){
    super(props);
  }
  render(){
    return (
      <div>
        <p>{this.props.name}</p>
      </div>
     );
  }
}
class List extends React.Component {
  render(){
   return(
    <div>
       {this.props.element}
       {this.props.element}
    </div>
   );
  }
}

ReactDOM.render(
  <List element = {<Link name = "working"/>}/>,
  document.getElementById('root')
);
serowy
źródło
0

Tak, możesz to zrobić za pomocą rekwizytów, możesz przekazać dane komponentu jako obiekt, np. Rekwizyty, a następnie wewnątrz komponentu możesz zaimportować inny komponent i dynamicznie powiązać z danymi prpps. czytaj więcej o komponencie reagującym

Dipankar Dutta
źródło
1
czy możesz opracować kod z zamieszczonego linku
Nelles