Skip to content

Instantly share code, notes, and snippets.

@kpunith8
Last active January 19, 2021 16:55
Show Gist options
  • Save kpunith8/da71fede5336ca9b6a8e3199ae727502 to your computer and use it in GitHub Desktop.
Save kpunith8/da71fede5336ca9b6a8e3199ae727502 to your computer and use it in GitHub Desktop.
React-Redux with hooks
import React, {useEffect} from 'react'
import {useSelector, useDispatch} from 'react-redux'
import {getAmount, changeAmount, changeCurrencyCode, getCurrencyCode} from './store'
const ExchangeRate = () => {
const amount = useSelector(getAmount) // or write inline selector, state => state.rates.amount
const code = useSelector(getCurrencyCode)
const dispatch = useDispatch()
const onAmountChange = e => dispatch(changeAmount(e.target.value)) // or write inline dispatch, {type: CHANGE_AMOUNT, payload: e.target.value}
// No need to use effect here, if you are dispatching an action before react renders
// useEffect(() => {
// dispatch(changeCurrencyCode(code))
// }, [code])
return (
<>
<label>Amount:</label>
<input onChange={onAmountChange} type='text' placeholder='Amount' value={amount} />
<h2>{amount}</h2>
<label>Currency Code:</label>
<input onChange={e => dispatch(changeCurrencyCode(e.target.value))} type='text' placeholder='Currency Code' value={code} />
<h3>{code}</h3>
</>
)
}
export default ExchangeRate
import React from 'react'
import ReactDOM from 'react-dom'
import {Provider} from 'react-redux'
import {store, changeCurrencyCode, getCurrencyCode } from './store'
import ExchangeRate from './exchange-rate'
// dispatch an initial action before react renders
store.dispatch(function getInitialRates(dispatch, getState) {
const state = getState()
const currencyCode = getCurrencyCode(state)
dispatch(changeCurrencyCode(currenencyCode))
})
const rootElement = document.getElementById('root')
ReactDOM.render(
<Provider store={store}>
<ExchangeRate />
<Provider>,
rootElement)
import {createStore, combineReducers, applyMiddleware} from 'redux'
import thunk from 'redux-thunk' // for async actions
const intialState = {
amount: 0,
currencyCode: 'USD',
currencyData: {USD: 0.0},
}
const ratesReducer = (state = intialState, action) => {
switch(action.type) {
case CHANGE_AMOUNT:
return {...state, amout: action.payload}
case CHANGE_CURRENCY_CODE:
return {...state, currencyCode: action.payload}
case GET_EXCHANGE_RATES:
return {...state, currencyData: action.payload}
default:
return state;
}
}
}
// selectors to use it in useSelector
export const getAmount = state => state.rates.amount
export const getCurrencyCode = state => state.rates.currencyCode
export const getCurrencyData = state => state.rates.currencyData
// Add action types and action creators as an API, so hat don't have to update in many places if it needs any changes
export const CHANGE_AMOUNT = 'changeAmount'
export const CHANGE_CURRENCY_CODE = 'changeCurrency'
export const GET_EXCHANGE_RATES = 'getExchangeRates'
export const changeAmount = amount => ({type: CHANGE_AMOUNT, payload: amount})
// Dispatching async actions using thunk middleware
// async actions using redux-thunk, instead of using useEffect
export const changeCurrencyCode = code => dispatch => {
dispatch({type: CHANGE_CURRENCY_CODE, payload: code})
// Call to API and dispatch another action when data is ready
getExchangeRates(code).then(res => {
dispatch({type: GET_EXCHANGE_RATES, payload: res})
})
}
// combine multiple reducers with namespace
export const store = createStore(combineReducers({rates: ratesReducer}), applyMiddleware(thunk))
// Wrap each the component using the provider so that unit cases will pass using react-testing-library
// It doesn't require you to wrap each component in a Provider while testing each component
import {render} from '@testing-library/react'
import {Provider} from 'react-redux'
import {store} from './store'
function ReduxProvider = ({children}) => {
return <Provider store={store}>{children}</Provider>
}
const reduxRender = (ui, options) =>
render(ui, {wrapper: ReduxProvider}, ...options)
// Re-export react testing library
export * from '@testing-library/react'
// Use the render exported from the test-utils in all the places instead of render function from @testing-library/react
export { reduxRender as render}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment