Reputation: 2415
I have this class component and want to rewrite it to stateless functional component with recompose
:
export default class Popular extends Component {
state = {
value: 0,
selected: "All",
repos: null
}
componentDidMount() {
this.handleSelected(this.state.selected)
}
handleChange = (e, value) => {
this.setState({ value })
}
handleSelected = lang => {
this.setState({
selected: lang,
repos: null
})
fetchPopularRepos(lang).then(repos => {
this.setState({
selected: lang,
repos
})
})
}
I'm struggling to combine onSelectLanguage
and onFetchRepos
in one function as in my code before refactoring. I don't know how to rewrite this for my componentDidMount function as well.
got this working with:
const enhance = compose(
withStateHandlers(initialState, {
onChangeLanguage,
onSelectLanguage
}),
lifecycle({
componentDidMount() {
fetchPopularRepos(this.props.selected).then(repos => {
this.setState({
repos
})
})
}
}),
lifecycle({
componentDidUpdate(prevProps) {
if (this.props.selected !== prevProps.selected) {
this.setState({ repos: null })
fetchPopularRepos(this.props.selected).then(repos => {
this.setState({
repos
})
})
}
}
})
)
These lifecycles don't look very sexy though. Not sure if this worth refactoring.
Upvotes: 1
Views: 1318
Reputation: 30360
Extending on the previous answer, you could use functional composition to combine the onFetchRepos
and onSelectLanguage
as required.
If I understand your requirements correctly, you should be able to achieve this by the following:
const initialState = {
value: 0,
selected: "All",
repos: null
}
const onChangeLanguage = props => (event, value) => ({
value
})
const onSelectLanguage = props => lang => ({
selected: lang
})
const onFetchRepos = props => (fetchPopularRepos(props.selected).then(repos => ({
repos
})))
// Combined function: onFetchRepos followed by call to onSelectLanguage
const onFetchReposWithSelectLanguage = props => onFetchRepos(props)
.then(response => props.onSelectLanguage(response))
// Minimal code to compose a functional component with both state handers and
// lifecycle handlers
const enhance = compose(
withStateHandlers(initialState, {
onChangeLanguage,
onSelectLanguage
}),
lifecycle({
componentDidMount() {
// Fetch repos and select lang on mount
onFetchReposWithSelectLanguage(this.props)
}
})
)
// Minimal code to compose a functional component with both state handers and
// lifecycle handlers
const enhance = compose(
withStateHandlers(initialState, {
onChangeLanguage,
onSelectLanguage,
setRepos
}),
lifecycle({
componentDidMount() {
// Reuse onSelectLanguage logic and call setState manually, use setState callback that
// fires after state is updated to trigger fetch based on newState.selected language
this.setState(onSelectLanguage(this.props.selected)(this.props), newState => {
fetchPopularRepos(newState.selected).then(repos => {
this.setState({
repos
})
})
})
}
})
)
Hope this helps you!
Upvotes: 0
Reputation: 30360
This looks like a case where you'd want to use the lifecycle()
method. I'm not a recompose
expert, however I think the following adjustments might achieve what you're after:
const onFetchPopularRepos = props => () => {
// Make sure the method returns the promise
return fetchPopularRepos(props.selected).then(repos => ({
repos: repos
}))
}
const withPopularReposState = withStateHandlers(initialState, {
onChangeLanguage,
onSelectLanguage
})
// Add a life cycle hook to fetch data on mount
const withLifecycle = lifecycle({
componentDidMount() {
// Update the state
onFetchPopularRepos(this.props).then(newState => this.setState(newState))
}
})();
// Compose the functional component with both lifecycle HOC
const enhance = withLifecycle(withPopularReposState)
Upvotes: 1