Closed carlosvillu closed 8 years ago
The parent component that renders <TransmitContainer />
should pass the variables
prop in.
Thx @RickWong
Sorry but I dont understand. Do you means something like this:
export default class App extends React.Component {
constructor(props) {
super(props);
}
render() {
const children = this.props.children;
console.log(children);
return (
<div className="App" style={{display: 'flex'}}>
<div className="Pokemons">
<Pokemons _onFetch={(data) => console.log('onFetch', data)}/>
</div>
<div>
{children ? <children variables={{id: this.props.params.pkdx_id}}/> : "Elige un pokemon"}
</div>
</div>
);
}
}
With a component like this, to show the details:
class PokemonDetail extends React.Component {
constructor(...args){
super(...args);
this.state = {pokemon: LOADING_POKEMON};
}
//componentDidMount(){
// pokemonAPI({id: this.props.params.pkdx_id}).then(pokemon => this.setState({pokemon}));
//}
componentWillReceiveProps(props){
this.setState({pokemon: LOADING_POKEMON});
pokemonAPI({id: props.params.pkdx_id}).then(pokemon => this.setState({pokemon}));
}
render(){
console.log('PokemonDetail Render')
return(
<div className="">
<div>
{!this.state.pokemon.sprites
? <img src="http://placeholdit.imgix.net/~text?txtsize=33&txt=P&w=84&h=84" width="84" height="84"/>
: this.state.pokemon.sprites.map((sprite, index) => <img key={index} src={`${POKEAPI_HOST}${sprite}`} width="84" height="84"/>)
}
</div>
<div>
{this.state.pokemon.name}
</div>
</div>
);
}
}
export default Transmit.createContainer(PokemonDetail, {
initialVariables: {
oPokemon: {},
id: null
},
fragments: {
pokemon: function({oPokemon, id}){
return pokemonAPI({id}).catch(console.error.bind(console))
}
}
});
And a rute files like this:
export default (
<Router>
<Route path="/" component={App}>
<Route path="pokemon/:pkdx_id" component={PokemonDetail}/>
</Route>
</Router>
);
But that didnt work, because this.props.children is not TransmitContainer.
BTW, the Pokemons component work fine:
class Pokemons extends React.Component {
constructor(...args){
super(...args);
this.state = {pokemons: this.props.pokemons || [] }
}
render(){
return(
<ul>
{
!this.state.pokemons.length ? <p>Cargando lista de pokemons</p>
: this.state.pokemons.map((pokemon, index) => {
return(
<li key={index}>
<Link to={`/pokemon/${pokemon.pkdx_id}`}>{pokemon.name}</Link>
</li>
);
})
}
</ul>
);
}
}
export default Transmit.createContainer(Pokemons, {
initialVariables: {
aPokemons: [],
},
fragments: {
pokemons: function({aPokemons}){
return fetch('http://pokeapi.co/api/v1/pokemon/?limit=50')
.then(resp => resp.json())
.then( pokemonsList => {
return aPokemons.concat(pokemonsList.objects)
})
.catch(console.error.bind(console));
}
}
});
Where is my misunderstood ?!
Create an extra routing component like this:
/**
* PokemonDetailRoute.js
*/
import PokemonDetail from "./PokemonDetail";
export default class PokemonDetailRoute extends React.Component {
render () {
// Pass `variables` prop with `pkdx_id` to the Transmit Container.
return <PokemonDetail variables={id: this.props.params.pkdx_id} />;
}
};
/**
* Routes.js
*/
// Configure the new routing component in React Router routes.
import PokemonDetailRoute from "./PokemonDetailRoute";
export default (
<Router>
<Route path="/" component={App}>
<Route path="pokemon/:pkdx_id" component={PokemonDetailRoute} />
</Route>
</Router>
);
I was looking for a way to do that too. @RickWong suggestion worked!
I've created a function to use in my application.
import React from 'react';
import Transmit from 'react-transmit';
import assign from 'libs/assign';
export default function (Component, options) {
return React.createClass({
displayName: (Component.displayName || Component.name) + "RouteWrapper",
render: function () {
const props = this.props;
const variables = {
history: props.history,
location: props.location,
params: props.params,
route: props.route,
routeParams: props.routeParams,
routes: props.routes,
children: props.children
};
return React.createElement(
Transmit.createContainer(Component, options),
assign({variables}, props)
);
}
});
}
Hi @lucasmogari
I have to donde something wrong, because for me is not working. Do you have any example online to see it ?!
@RickWong Will be possible use the instance of the component like the fragment context ?!
Hi @carlosvillu, I created an example here: https://github.com/lucasmogari/react-isomorphic-starterkit
Hi @lucasmogari, thx for sharing. But in my case, the problems come when I have more than one route. Now my router looks like this:
<Router>
<Route path="/" component={App}>
<IndexRoute component={Index} />
<Route path="pokemon/:pkdx_id" component={PokemonDetailRoute}/>
<Route path="*" component={NotFound} />
</Route>
</Router>
I don't know why the fragments are called several times in the same render. First it renders the page and then resolves the fragments. I don't know exactly why; I suppose that is my fail. But I really don't know what is failing.
Here is what I tried:
https://github.com/carlosvillu-com/intro-isomorphic-app/tree/feature/isomorphic/app
:(
@carlosvillu There is no need to track this.state.pokemon
here https://github.com/carlosvillu-com/intro-isomorphic-app/blob/feature/isomorphic/app/components/pokemonDetail.js#L26
Because Transmit will not render the component if it hasn't resolved this.props.pokemon
anyway. So always use this.props.pokemon
.
You should pass the renderLoading
prop on this line: https://github.com/carlosvillu-com/intro-isomorphic-app/blob/feature/isomorphic/app/routes.js#L17
return <PokemonDetail variables={{id: this.props.params.pkdx_id}} renderLoading={
() => <PokemonDetail pokemon={[LOADING_POKEMON]} /> // Render loading PokemonDetail by passing the `pokemon` prop with hard-coded data.
} />;
Thx @RickWong I will do the changes and figure out why I have severals reloads when I go to /pokemon/:id page.
I'm closing this issue. New questions can go in new issues.
Thx @RickWong for the help :)
I have a component which, within its
ComponentDidMount
function, usesthis.props.params.id
to make an asynchronous call to an API and show results.I'd like to replicate this behavior in a fragment function but the execution context (this) does not represent the component instance but the function. Therefore, I can't access
this.props
.What should I do to use the information provided by React-Router within the fragment functions?
Thx!