Redux is one of the most popular state-management libraries and although not specific to React, it is widely used with it. This is why the author of Preact has released a package called preact-redux, which is a simple wrapper around the main react-redux package that enables it to be used in a Preact application without any other changes to your codebase. In this lesson we refactor a stateful component to use Redux + Redux-thunk.
Install:
yarn add redux redux-thunk preact-redux
Set up:
import {h, render} from 'preact';import {Provider} from 'preact-redux';import thunk from 'redux-thunk';import {createStore, applyMiddleware, compose} from 'redux';import App from './components/App';import reducer from './reducer';const initialState = { loading: true, user: null};const composeEnhancers = typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize... }) : compose;const store = createStore(reducer, initialState, composeEnhancers(applyMiddleware(thunk)));render(, document.querySelector('main'));
Reducer:
export default function (state, action) { switch (action.type) { case 'FETCH_USER': return { user: null, loading: true }; case 'USER_FETCHED': return { user: action.payload, loading: false }; default: return state; }}
Action creator:
const config = { url: 'https://api.github.com/users'};export function fetchUser(username) { return function (dispatch) { dispatch({type: 'FETCH_USER'}); fetch(`${config.url}/${username}`) .then(resp => resp.json()) .then(user => { dispatch({type: 'USER_FETCHED', payload: user}) }) .catch(err => console.error(err)); }}
Component:
import {h, Component} from 'preact';import User from './User';import {fetchUser} from '../actions';import {connect} from 'preact-redux';export class Profile extends Component { componentDidMount() { const username = this.props.match.params.user; this.props.fetchUser(username); } render({loading, userState, user}) { return ({(loading && !userState) ?); }}const mapStateToProps = (state) => { return { userState: state.user, loading: state.loading };};const mapDispatchToProps = (dispatch) => { return { fetchUser: (username) => dispatch(fetchUser(username)) };};export default connect( mapStateToProps, mapDispatchToProps)(Profile);Fetching {user}'s profile
:}